Android 13 Launcher 基礎(chǔ)認識(一)

學(xué)習(xí)筆記:


Android 10.0 launcher 啟動流程
Android 13 Launcher 基礎(chǔ)認識(一)
Android 13 Launcher 數(shù)據(jù)加載分析(二)
Android 13 Launcher3 數(shù)據(jù)庫及Workspace 的數(shù)據(jù)加載與綁定(三)

一、Launcher 簡介

Launcher 是 Android 系統(tǒng)不可缺少的部分,我們通常稱之為 Android 系統(tǒng)的桌面,它在 Android 系統(tǒng)中起著重要的作用。

  • Launcher 是 Android 系統(tǒng)的啟動器。在 Launcher 中可以啟動你想要使用的應(yīng)用程序。
  • Launcher 也是應(yīng)用程序的管理器。可用來對應(yīng)用程序進行基礎(chǔ)的管理,比如刪除或者展示應(yīng)用程序。
  • Launcher 更重要的意義在于它是一個桌面。在 Android 的桌面上,你可以放置各種快捷方式、桌面小部件,也可以通過 Launcher 更換壁紙,使你的桌面更炫更便利更加個性化。
二、Launcher 結(jié)構(gòu)

在 Launcher 中主要有兩大組件:

  • UI組件:桌面(Workspace)、應(yīng)用程序菜單(Allapps)、快捷啟動欄(Hotseat)、搜索和頁面指示條、快捷菜單。
  • 桌面組件:應(yīng)用程序的快捷方式及相關(guān)視圖實現(xiàn)(DeepShortcuts)、文件夾及相關(guān)視圖實現(xiàn)、桌面小部件及相關(guān)組件(Widgets)。
UI組件.png
桌面組件.png
三、launcher 啟動

參考Android系統(tǒng)開機到Launcher啟動流程分析Android 10.0 launcher啟動流程。

四、主要文件和類
  • Launcher.java:launcher中主要的activity。

  • LoaderTask.java: 可運行用于加載啟動器內(nèi)容的線程: 工作區(qū)圖標 、小部件 、所有應(yīng)用程序圖標 、應(yīng)用程序快捷方式。

  • LauncherAppState.java:用于存儲全局變量,比如:緩存(各種cache),維護內(nèi)存數(shù)據(jù)的類(LauncherModel)。

  • DragLayer.java:launcher layout的rootview。DragLayer實際上也是一個抽象的界面,用來處理拖動和對事件進行初步處理然后按情況分發(fā)下去,角色是一個controller。它首先用onInterceptTouchEvent(MotionEvent)來攔截所有的touch事件,如果是長按item拖動的話不把事件傳下去,直接交由onTouchEvent()處理,這樣就可以實現(xiàn)item的移動了,如果不是拖動item的話就把事件傳到目標view,交有目標view的事件處理函數(shù)做相應(yīng)處理。如過有要對事件的特殊需求的話可以修改onInterceptTouchEvent(MotionEvent)來實現(xiàn)所需要的功能。

  • DragController.java:為Drag定義的一個接口。包含一個接口,兩個方法和兩個靜態(tài)常量。接口為DragListener(包含onDragStart(),onDragEnd()兩個函數(shù)),onDragStart()是在剛開始拖動的時候被調(diào)用,onDragEnd()是在拖動完成時被調(diào)用。在launcher中典型的應(yīng)用是DeleteZone,在長按拖動item時調(diào)用onDragStart()顯示,在拖動結(jié)束的時候onDragEnd()隱藏。兩個函數(shù)包括startDrag()和setDragItemInfo().startDrag()用于在拖動是傳遞要拖動的item的信息以及拖動的方式,setDragItemInfo()用于傳遞item的參數(shù)信息(包括位置以及大小)。兩個常量為DRAG_ACTION_MOVE,DRAG_ACTION_COPY來標識拖動的方式,DRAG_ACTION_MOVE為移動,表示在拖動的時候需要刪除原來的item,DRAG_ACTION_COPY為復(fù)制型的拖動,表示保留被拖動的item。

  • LauncherModel.java:輔助的文件。里面有許多封裝的對數(shù)據(jù)庫的操作。包含幾個線程,其中最主要的是ApplicationsLoader和DesktopItemsLoader。ApplicationsLoader在加載所有應(yīng)用程序時使用,DesktopItemsLoader在加載workspace的時候使用。其他的函數(shù)就是對數(shù)據(jù)庫的封裝,比如在刪除,替換,添加程序的時候做更新數(shù)據(jù)庫和UI的工作。

  • Workspace.java:抽象的桌面。由N個celllaout組成,從cellLayout更高一級的層面上對事件的處理。

  • LauncherProvider.java:launcher的數(shù)據(jù)庫,里面存儲了桌面的item的信息。在創(chuàng)建數(shù)據(jù)庫的時候會loadFavorites(db)方法,loadFavorites()會解析xml目錄下的default_workspace.xml文件,把其中的內(nèi)容讀出來寫到數(shù)據(jù)庫中,這樣就做到了桌面的預(yù)制。

  • CellLayout.java:組成workspace的view,繼承自viewgroup,既是一個dragSource,又是一個dropTarget,可以將它里面的item拖出去,也可以容納拖動過來的item。在workspace_screen里面定了一些它的view參數(shù)。

  • ItemInfo.java:對item的抽象,所有類型item的父類,item包含的屬性有id(標識item的id),cellX(在橫向位置上的位置,從0開始),cellY(在縱向位置上的位置,從0開始) ,spanX(在橫向位置上所占的單位格),spanY(在縱向位置上所占的單位格),screen(在workspace的第幾屏,從0開始),itemType(item的類型,有widget,search,application等),container(item所在的)。

  • LauncherSettings.java:字符串的定義。數(shù)據(jù)庫項的字符串定義,另外在這里定義了container的類型,還有itemType的定義,除此還有一些特殊的widget(如search,clock的定義等)的類型定義。

五、launcher 源碼分析

launcher.java 是 launcher 主要、第一個啟動的 activity,在其里面進行顯示、初始化一些 View。
launcher#onCreate()

// launcher.java
    protected void onCreate(Bundle savedInstanceState) {
        // 省略部分代碼......
        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT,
                TraceHelper.FLAG_UI_EVENT);
        if (DEBUG_STRICT_MODE) {
            //StrictMode被稱為嚴苛模式,google提供用來進行測試的類
            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
        LauncherAppState app = LauncherAppState.getInstance(this);
        mOldConfig = new Configuration(getResources().getConfiguration());
         // 獲取LauncherModel實例
        mModel = app.getModel();

        mRotationHelper = new RotationHelper(this);
        InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
        // 初始化手機固件信息對象DeviceProfile
        initDeviceProfile(idp);
        idp.addOnChangeListener(this);
        // 獲取sharedPreferences
        mSharedPrefs = Utilities.getPrefs(this);
        // 獲取IconCache實例,此類主要保存圖標信息
        mIconCache = app.getIconCache();
        mAccessibilityDelegate = createAccessibilityDelegate();
        // 拖拽
        mDragController = new LauncherDragController(this);
        mAllAppsController = new AllAppsTransitionController(this);
        mStateManager = new StateManager<>(this, NORMAL);

        mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);

        // 獲取AppWidgetManager實例,用來管理widge
        mAppWidgetManager = new WidgetManagerHelper(this);
        mAppWidgetHost = createAppWidgetHost();
        mAppWidgetHost.startListening();

        // 設(shè)置布局
        inflateRootView(R.layout.launcher);
        // 初始化View,進行各種View的初始化事件綁定
        setupViews();
        crossFadeWithPreviousAppearance();
        mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);

        boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this);
        // 對于狀態(tài)進行判斷,我們不需要進行任何的配置
        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);
            }
        }
        // 加載、綁定數(shù)據(jù)(這里與之前版本的 startLoader() 作用一樣)
        // 如果沒有綁定則進行加載、綁定數(shù)據(jù)
        if (!mModel.addCallbacksAndLoad(this)) {
            if (!internalStateHandled) {
                Log.d(BAD_STATE, "Launcher onCreate not binding sync, prevent drawing");
                // 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;
            }
        }

        // For handling default keys
        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);

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

        // 注冊屏幕關(guān)閉廣播
        registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));

        getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.onCreate(savedInstanceState);
        }
        mOverlayManager = getDefaultOverlay();
        PluginManagerWrapper.INSTANCE.get(this).addPluginListener(this,
                LauncherOverlayPlugin.class, false /* allowedMultiple */);

        mRotationHelper.initialize();
        TraceHelper.INSTANCE.endSection(traceToken);

        mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(
                () -> getStateManager().goToState(NORMAL));

        if (Utilities.ATLEAST_R) {
            getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
        }
        setTitle(R.string.home_screen);
    }

從代碼中可以看出,首先調(diào)用了 LauncherAppState.getInstance(this) 來初始化一個單例對象 ,而LauncherAppState 里面保存了一些比較常用的對象,方便其他地方通過單例來獲取,比如 IconCache、LauncherModel 等;并且注冊了廣播監(jiān)聽器和 ContentObserver ;設(shè)置布局 launcher.xml,調(diào)用 setupViews() 又是一些 View 的初始化,設(shè)置回調(diào)監(jiān)聽等。

總結(jié)一下 onCreate() 的工作:初始化對象、加載布局、注冊一些事件監(jiān)聽、以及開啟數(shù)據(jù)加載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容