Launcher的啟動流程

系統(tǒng)怎么啟動Launcher的

Activity會調(diào)用startHomeActivityLocked方法,此方法會創(chuàng)建一個Intent疼约,mTopAction和mTopData傳給Intent,其中mTopAction為Intent.ACTION_MAIN缴渊,Intent的category為android.intent.category.Home矢洲。而Launcher的AndroidMainfest.xml文件里面給Launcher定義的category也是Home绅喉,根據(jù)匹配原則模狭,這樣就會啟動這個Launcher颈抚。

Launcher的intent-filter配置:

        <activity
            android:name="com.android.launcher3.Launcher"
            ...
            android:exported="true"
            android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.SHOW_WORK_APPS" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY"/>
                <category android:name="android.intent.category.LAUNCHER_APP" />
            </intent-filter>
        </activity>
Launcher類的onCreate初始化流程解析
protected void onCreate(Bundle savedInstanceState) {
        //創(chuàng)建啟動性能日志記錄器(mStartupLatencyLogger)线梗,用于記錄Launcher啟動的性能數(shù)據(jù)嘱支。根據(jù)啟動類型(冷啟動、設(shè)備重啟丽蝎、熱啟動)進行初始化反砌。
        mStartupLatencyLogger = createStartupLatencyLogger(
                sIsNewProcess
                        ? LockedUserState.get(this).isUserUnlockedAtLauncherStartup()
                            ? COLD
                            : COLD_DEVICE_REBOOTING
                        : WARM);
        sIsNewProcess = false;
        mStartupLatencyLogger
                .logStart(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
                .logStart(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
        // Only use a hard-coded cookie since we only want to trace this once.
        if (Utilities.ATLEAST_S) {
            Trace.beginAsyncSection(
                    DISPLAY_WORKSPACE_TRACE_METHOD_NAME, DISPLAY_WORKSPACE_TRACE_COOKIE);
            Trace.beginAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
                    DISPLAY_ALL_APPS_TRACE_COOKIE);
        }
        TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT);

  //如果開啟了DEBUG_STRICT_MODE雾鬼,則設(shè)置StrictMode策略萌朱,用于檢測一些運行時錯誤宴树,如磁盤讀寫、網(wǎng)絡(luò)等問題晶疼。
        if (DEBUG_STRICT_MODE) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()   // or .detectAll() for all detectable problems
                    .penaltyLog()
                    .build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects()
                    .detectLeakedClosableObjects()
                    .penaltyLog()
                    .penaltyDeath()
                    .build());
        }

        super.onCreate(savedInstanceState);

        //獲取LauncherAppState實例酒贬,該實例負(fù)責(zé)管理Launcher的狀態(tài)和數(shù)據(jù)。
        LauncherAppState app = LauncherAppState.getInstance(this);
        mModel = app.getModel();

        //初始化設(shè)備配置翠霍,包括屏幕的旋轉(zhuǎn)信息和設(shè)備的規(guī)格信息锭吨。
        mRotationHelper = new RotationHelper(this);
        InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
        initDeviceProfile(idp);
        idp.addOnChangeListener(this);
        mSharedPrefs = LauncherPrefs.getPrefs(this);
        mIconCache = app.getIconCache();
        mAccessibilityDelegate = createAccessibilityDelegate();

        //初始化Launcher的視圖(如桌面、小部件寒匙、搜索欄等)和控制器(如拖動控制器零如、應(yīng)用程序列表控制器等)。
        initDragController();
        mAllAppsController = new AllAppsTransitionController(this);
        mStateManager = new StateManager<>(this, NORMAL);

        mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);

        // TODO: move the SearchConfig to SearchState when new LauncherState is created.
        mBaseSearchConfig = new BaseSearchConfig();

        setupViews();

       //初始化小部件管理器和小部件持有者锄弱,用于管理和顯示桌面上的小部件考蕾。
        mAppWidgetManager = new WidgetManagerHelper(this);
        mAppWidgetHolder = createAppWidgetHolder();
        mAppWidgetHolder.startListening();

        mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);

        boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this);
        if (internalStateHandled) {
            if (savedInstanceState != null) {
                // InternalStateHandler has already set the appropriate state.
                // We dont need to do anything.
                savedInstanceState.remove(RUNTIME_STATE);
            }
        }
        restoreState(savedInstanceState);
        mStateManager.reapplyState();

        if (savedInstanceState != null) {
            int[] pageIds = savedInstanceState.getIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS);
            if (pageIds != null) {
                mPagesToBindSynchronously = IntSet.wrap(pageIds);
            }
        }

        //調(diào)用LauncherModel的addCallbacksAndLoad方法,注冊回調(diào)并加載桌面數(shù)據(jù)会宪。
        mStartupLatencyLogger.logWorkspaceLoadStartTime();
        if (!mModel.addCallbacksAndLoad(this)) {
            if (!internalStateHandled) {
                // If we are not binding synchronously, pause drawing until initial bind complete,
                // so that the system could continue to show the device loading prompt
                mOnInitialBindListener = Boolean.FALSE::booleanValue;
            }
        }

        // 設(shè)置默認(rèn)的鍵盤模式
        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);

        //設(shè)置當(dāng)前Activity的內(nèi)容視圖為Launcher的根視圖肖卧。
        setContentView(getRootView());
        //初始化Compose相關(guān)配置。
        ComposeInitializer.initCompose(this);

        if (mOnInitialBindListener != null) {
            getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener);
        }
        getRootView().dispatchInsets();

        // 注冊監(jiān)聽器以監(jiān)聽屏幕的開啟和關(guān)閉狀態(tài)掸鹅。
        ScreenOnTracker.INSTANCE.get(this).addListener(mScreenOnListener);
        getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.onCreate(savedInstanceState);
        }

        mOverlayManager = getDefaultOverlay();

       //注冊插件監(jiān)聽器塞帐,用于監(jiān)聽Launcher Overlay插件的狀態(tài)拦赠。
        PluginManagerWrapper.INSTANCE.get(this).addPluginListener(this,
                LauncherOverlayPlugin.class, false /* allowedMultiple */);

        //初始化屏幕旋轉(zhuǎn)輔助類,用于管理屏幕旋轉(zhuǎn)相關(guān)邏輯葵姥。
        mRotationHelper.initialize();
        TraceHelper.INSTANCE.endSection();

        if (Utilities.ATLEAST_R) {
            getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
        }
        setTitle(R.string.home_screen);
        
   //結(jié)束啟動性能日志記錄器荷鼠,記錄Launcher啟動的結(jié)束時間。
mStartupLatencyLogger.logEnd(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
    }
部分代碼解析:
LauncherAppState.getInstance
 LauncherAppState app = LauncherAppState.getInstance(this);
        // Load configuration-specific DeviceProfile
        mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);

創(chuàng)建LauncherAppState對象榔幸,重點是根據(jù)手機硬件參數(shù)生成桌面參數(shù)(在系列第二篇中講到的default_workspace.xml就是根據(jù)獲取的硬件參數(shù)來進行適配選擇的)颊咬。

不同的手機顯示的Launcher布局是一樣的,但是其中真正顯示的圖標(biāo)牡辽,每個畫面的像素點大小是不同的喳篇,Launcher需要根據(jù)手機的尺寸密度等硬件參數(shù),計算出更多的信息态辛,這一步就是將和手機硬件掛鉤的參數(shù)都獲取出來麸澜。

一方面它定義了Launcher的很多屬性,圖標(biāo)大小奏黑,尺寸等炊邦。
另一方面在可用間距發(fā)生改變時會調(diào)用UpdateIconSize方法,重新計算更新圖標(biāo)大惺焓贰:行列數(shù)是根據(jù)配置的行列數(shù)馁害,圖標(biāo)大小,表格間距等計算出來的蹂匹,如果想要改變行列數(shù)碘菜,可以適當(dāng)把圖標(biāo)縮小放大,間距增大或減小限寞。

生成桌面分布局
setupViews();

將桌面的各個部分都創(chuàng)建對象忍啸,綁定一些事件監(jiān)聽器等,進一步基本將桌面的各個UI子模塊都定義完成履植。

Launcher的onCreate方法之后

Activity.onCreate在接近結(jié)尾的地方調(diào)用了mModel的startLoader方法计雌,他把LoaderTask對象放到了工作線程中。

sWorkThread會執(zhí)行LoaderTask的run方法玫霎,run方法里面最重要的就屬于loadAndBindWorkspace方法了凿滤。在上面的圖中,我已經(jīng)畫出了他的功能庶近,先是在數(shù)據(jù)庫讀取數(shù)據(jù)翁脆,看看有什么需要增加,有什么需要刪除拦盹;再在界面上顯示鹃祖。顯示完了之后桌面其實也就啟動完了。

  • loadWorkspace:
    loadWorkspace有將近400行,挺多的恬口,其實做的事情就是遍歷數(shù)據(jù)庫里的每條記錄校读,判斷他的類型,生成對應(yīng)的ItemInfo對象(ShortcutInfo祖能,F(xiàn)olderInfo歉秫,LauncherAppWidgetInfo)

  • bindWorkspace:
    在bindWorkspace里面,用了一個很重要的Callback接口养铸,Launcher.java實現(xiàn)了這些接口雁芙,用于更新UI。bindWorkspace新建了幾個對象都是current,other形式的钞螟,這個current代表的是當(dāng)前屏的ItemInfo兔甘,other代表的其他屏的ItemInfo,為了加載時候不讓用戶感覺很慢鳞滨,就先把當(dāng)前屏的顯示出來洞焙,再顯示其他的,這個顯示的工作都交給了bindWorkspaceItems方法拯啦。bindWorkspaceItems會分別加載圖標(biāo)澡匪,小工具,和文件夾褒链。

參考:
http://www.reibang.com/p/5d4e5b5c6804
https://fookwood.com/launcher-start-process-2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唁情,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子甫匹,更是在濱河造成了極大的恐慌甸鸟,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赛惩,死亡現(xiàn)場離奇詭異哀墓,居然都是意外死亡,警方通過查閱死者的電腦和手機喷兼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來后雷,“玉大人季惯,你說我怎么就攤上這事⊥瓮唬” “怎么了勉抓?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長候学。 經(jīng)常有香客問我藕筋,道長,這世上最難降的妖魔是什么梳码? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任隐圾,我火速辦了婚禮伍掀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暇藏。我一直安慰自己蜜笤,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布盐碱。 她就那樣靜靜地躺著把兔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瓮顽。 梳的紋絲不亂的頭發(fā)上县好,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音暖混,去河邊找鬼聘惦。 笑死,一個胖子當(dāng)著我的面吹牛儒恋,可吹牛的內(nèi)容都是我干的善绎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼诫尽,長吁一口氣:“原來是場噩夢啊……” “哼禀酱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起牧嫉,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤剂跟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后酣藻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體曹洽,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年辽剧,在試婚紗的時候發(fā)現(xiàn)自己被綠了送淆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡怕轿,死狀恐怖偷崩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撞羽,我是刑警寧澤阐斜,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站诀紊,受9級特大地震影響谒出,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一笤喳、第九天 我趴在偏房一處隱蔽的房頂上張望为居。 院中可真熱鬧,春花似錦莉测、人聲如沸颜骤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忍抽。三九已至,卻和暖如春董朝,著一層夾襖步出監(jiān)牢的瞬間鸠项,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工子姜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留祟绊,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓哥捕,卻偏偏與公主長得像牧抽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子遥赚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容