Android桌面Launcher源碼淺析

来源:https://www.cnblogs.com/anywherego/p/18225051
-Advertisement-
Play Games

在Android啟動過程-萬字長文(Android14)中介紹了Android系統的啟動過程,本篇文章將繼續介紹桌面應用Launcher。 一、Launcher介紹 在Android啟動過程-萬字長文(Android14)中提到Launcher是Android系統啟動後,由SystemServerA ...


Android啟動過程-萬字長文(Android14)中介紹了Android系統的啟動過程,本篇文章將繼續介紹桌面應用Launcher。

一、Launcher介紹

  • Android啟動過程-萬字長文(Android14)中提到Launcher是Android系統啟動後,由SystemServerActivity Manager Service (AMS)載入的第一個應用程式
  • Launcher又被稱為桌面程式,負責Android桌面的啟動和管理
  • 用戶使用的應用程式(App)都是通過Launcher來啟動的

二、下載及編譯

2.1 下載

  • 使用Git下載Launcher源碼:
git clone https://android.googlesource.com/platform/packages/apps/Launcher3
  • 進入項目目錄
cd Launcher3
  • 切換到Android14分支
git checkout android14-release

2.2 編譯

使用AndroidStudio編譯下載好的Launcher3工程

編譯過程中遇到問題及解決方案可以參考以下博客:

三、源碼解析

3.1 AndroidManifest.xml

在項目根目錄的AndroidManifest.xml,定義了Launcher做為桌面程式的屬性:

<application>
    <activity
        android:name="com.android.launcher3.Launcher"
        android:launchMode="singleTask">
        <intent-filter>
            <category android:name="android.intent.category.HOME" />
        </intent-filter>
    </activity>
</application>
  • android.intent.category.HOME: 告訴系統這是一個啟動器(Launcher)應用程式,系統在初始化完成後會通過ActivityTaskManagerServicegetHomeIntent方法獲取和啟動桌面程式。具體可參見Android啟動過程-萬字長文(Android14)
  • 開發人員也可以自己開發一個桌面程式(如微軟桌面),用戶安裝完成後,可以在系統設置中修改預設啟動的桌面程式

3.2 Launcher.java

Launcher.java是Launcher的啟動頁面,負責資源初始化和桌面UI創建

3.2.1 onCreate方法

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 獲取 LauncherAppState 實例和模型
    LauncherAppState app = LauncherAppState.getInstance(this);
    mModel = app.getModel();
    
    // 初始化不變的設備配置文件
    InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
    initDeviceProfile(idp);
    idp.addOnChangeListener(this);

    // 獲取共用首選項和圖標緩存
    mSharedPrefs = LauncherPrefs.getPrefs(this);
    mIconCache = app.getIconCache();

    // 創建無障礙代理
    mAccessibilityDelegate = createAccessibilityDelegate();

    // 初始化拖動控制器
    initDragController();
    
    // 創建所有應用程式控制器
    mAllAppsController = new AllAppsTransitionController(this);
    
    // 創建狀態管理器
    mStateManager = new StateManager<>(this, NORMAL);

    // 創建引導首選項
    mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);

    // 設置視圖
    setupViews();

    // 初始化Widget
    mAppWidgetManager = new WidgetManagerHelper(this);
    mAppWidgetHolder = createAppWidgetHolder();
    mAppWidgetHolder.startListening();

    // 設置內容視圖
    setContentView(getRootView());
    ComposeInitializer.initCompose(this);

}

3.2.2 setupViews方法

protected void setupViews() {
    // 創建根視圖
    inflateRootView(R.layout.launcher);

    // 獲取拖動層和焦點處理器
    mDragLayer = findViewById(R.id.drag_layer);
    mFocusHandler = mDragLayer.getFocusIndicatorHelper();
    
    // 獲取工作區、總覽面板和Hotseat
    mWorkspace = mDragLayer.findViewById(R.id.workspace);
    mWorkspace.initParentViews(mDragLayer);
    mOverviewPanel = findViewById(R.id.overview_panel);
    mHotseat = findViewById(R.id.hotseat);
    // 將工作區設置為Hotseat
    mHotseat.setWorkspace(mWorkspace);

    // 設置拖動層
    mDragLayer.setup(mDragController, mWorkspace);

    // 設置工作區
    mWorkspace.setup(mDragController);
    // 在工作區綁定之前,確保我們將壁紙偏移鎖定到預設狀態,否則在RTL中我們將更新錯誤的偏移量
    mWorkspace.lockWallpaperToDefaultPage();
    mWorkspace.bindAndInitFirstWorkspaceScreen();
    mDragController.addDragListener(mWorkspace);

    // 獲取搜索/刪除/卸載欄
    mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar);

    // 設置應用程式視圖
    mAppsView = findViewById(R.id.apps_view);
    mAppsView.setAllAppsTransitionController(mAllAppsController);

    // 設置拖動控制器(拖動目標必須按優先順序的相反順序添加)
    mDropTargetBar.setup(mDragController);
    mAllAppsController.setupViews(mScrimView, mAppsView);

    // 如果啟用了點分頁,則設置工作區的分頁指示器
    if (SHOW_DOT_PAGINATION.get()) {
        mWorkspace.getPageIndicator().setShouldAutoHide(true);
        mWorkspace.getPageIndicator().setPaintColor(
                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)
                        ? Color.BLACK
                        : Color.WHITE);
    }
}

  • Workspace:工作區,也是我們常說的桌面區域,包括搜索框,桌面,壁紙
  • AppsView:應用程式列表
  • Widget:小組件

三、Workspace、AppsView和Widget示例

3.1 Workspace(工作區)

  • 結構說明

3.2 AppsView(應用程式視圖)

3.3 Widget(小組件)

四、點擊App圖標的事件響應

4.1 觸發ItemClickHandler的onClick方法

  • ItemClickHandler負責處理桌面應用圖標的點擊事件。
  • 桌面圖標的點擊事件最終會觸發ItemClickHandleronClick方法
  • onClick方法最終會觸發startAppShortcutOrInfoActivity方法
/**
 * Class for handling clicks on workspace and all-apps items
 */
public class ItemClickHandler {
    private static void onClick(View v) {
        startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
    }
    
    // 通知launcher啟動Activity
    private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
        launcher.startActivitySafely(v, intent, item);
    }
}

4.2 Launcher通知系統啟動App

Launcher.java的startActivitySafely方法中調用ActivityContext.java的startActivitySafely方法

public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
    RunnableList result = super.startActivitySafely(v, intent, item);
}

ActivityContext.java的startActivitySafely方法中調用了

public interface ActivityContext {
        default RunnableList startActivitySafely(
            View v, Intent intent, @Nullable ItemInfo item) {
            if (isShortcut) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            }
        }
        
        default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
            if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
                    // 通過快捷方式啟動
                    startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
                } else {
                    // 普通方式啟動,應用程式走這個分支
                    ((Context) this).startActivity(intent, optsBundle);
                }
        }
}

Android 應用快捷方式(Shortcut)官方文檔

最終通過frameworks/base/core/java/android/app/Activity.java 源碼地址中的startActivity方法啟動了對應的應用程式。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • MySQL死鎖接觸少,但面試又經常被問到怎麼辦? 最近有小伙伴在面試的時候,被問了MySQL死鎖,如何解決? 雖然也回答出來了,但是不夠全面體系化, 所以,小北給大家做一下系統化、體系化的梳理,幫助大家在面試過程中能夠脫穎而出,拿到自己心儀的Offer 插播一條:如果你近期準備面試跳槽,建議在htt ...
  • 隨著大數據技術和人工智慧的發展,企業逐漸意識到構建一個集中化的指標管理平臺的必要性。這樣的平臺旨在解決幾個核心問題:首先,確保所有部門都能通過統一的入口提交指標需求,實現需求的透明化管理;其次,建立完善的指標管理體系,涵蓋從需求定義、模型設計、數據集成、開發實施到應用監控的全鏈條;第三,通過自動化和 ...
  • 如何對MySQL中的資料庫進行優化,如何優化數據表中的數據類型、刪除重覆、冗餘索引;如何設計資料庫,資料庫的範式要求。如何對數據表進行分析、檢查、優化、拆分。 ...
  • 在當今的互聯網時代,隨著用戶數量和請求量的不斷增加,系統的性能和穩定性面臨著巨大的挑戰。限流演算法作為保障系統穩定性的重要手段之一,被廣泛應用於各種服務和應用中。限流的核心目的是對某一時間視窗內的請求數進行限制,保持系統的可用性和穩定性,防止因流量暴增而導致的系統運行緩慢或宕機。 常見限流演算法對比 常 ...
  • 【標題】ODBC驅動類問題定位方法 【需求分類】故障分析 【關鍵字】ODBC 【需求描述】由於我們的ODBC介面目前尚不完善,經常會遇見ODBC介面能力不足導致應用功能無法運行的問題,需要定位手段確定底層是哪個介面報錯 【需求原因分析】方便一線資料庫管理員初步分析故障 【分析方法】 ● 由於我們的O ...
  • MySQL語句優化包括創建合適的索引、使用覆蓋索引、避免不必要的子查詢、通過 EXPLAIN 分析查詢計劃、進行批量操作、減少鎖定範圍、使用預編譯語句和查詢緩存,以顯著提高查詢性能和資料庫運行效率。 ...
  • 一、概述 1.什麼是語言基礎類庫 語言基礎類庫,也稱為標準庫或核心庫,是編程語言提供的一組內置的基礎功能和常用工具的集合。它通常包含了各種數據結構、演算法、輸入輸出處理、字元串處理、日期時間處理、文件操作、網路通信等功能,為開發者提供了便捷的編程介面,以減少開發工作量並提高代碼的可讀性和可維護 ...
  • 前言 請求響應是指客戶端發送請求給伺服器,伺服器接收到請求後返回的響應。響應包含了伺服器處理請求的結果,並將結果返回給客戶端。 頁面調試是指在開發過程中,通過調試工具分析頁面的運行狀況,查找問題和修複錯誤。常用的頁面調試工具包括瀏覽器的開發者工具和調試插件,可以檢查頁面的網路請求、HTML代碼、 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...