Launcher 3デスクトップロードプロセス分析(下)

30084 ワード

上記Launcher 3デスクトップロードプロセス分析(上)では、LauncherModelがLoaderTaskロードデータを作成しているのを見て、引き続き下を見てみましょう.
LoaderTask
LoaderTaskを作成します.flagsはPagedViewです.INVALID_RESTORE_PAGE値-1001はrunメソッドがどのように実行されるかを見てみましょう.

private class LoaderTask implements Runnable {
   
    LoaderTask(Context context, int flags) {
        mContext = context;
        mFlags = flags;
    }

    public void run() {
        ...
        
        keep_running: {
            if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
            loadAndBindWorkspace();

            if (mStopped) {
                break keep_running;
            }

            waitForIdle();

            // second step
            if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
            loadAndBindAllApps();
        }
        ...
    }
}
        

mStoppedの状態に基づいていくつかの事前の判断を行うほか、最初に実行されるのはloadAndBindWorkspace()メソッドであり、画面数、アプリケーションデータ、widgetコンポーネント情報など、Workspaceのデータをロードおよびバインドし、waitForIdle()を呼び出してloadAndBindWorkspace()で作成されたサブスレッドの実行を待つ.mStoppedとmLoadAndBindStep Finishedの状態を変更してloadAndBindAllApps()を実行し、すべてのアプリケーションをロードし、アプリケーション全体のロードプロセスを完了します.全体の流れは上のrun方法で、具体的な詳細は一歩一歩見てみましょう.
Workspace
Workspaceとは何ですか?Launcher 3のメインレイアウトファイルlauncher.を自分で見てください.xmlレイアウトは明らかですが、workspaceはLauncherのワークベンチで、アプリケーションデータ、widgetコンポーネントデータ、フォルダデータ、その他の機能を搭載しています.
ワークスペースをロードするプロセスは2つのステップに分かれています.
  • データのロード、loadWorkspace()
  • バインドworkspace,bindWorkspace()
  • プロセスは次のとおりです.
    
        private void loadAndBindWorkspace() {
            mIsLoadingAndBindingWorkspace = true;        
            // Load the workspace
            if (DEBUG_LOADERS) {
                Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);
            }
    
            if (!mWorkspaceLoaded) {
                loadWorkspace();
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return;
                    }
                    mWorkspaceLoaded = true;
                }
            }
    
            // Bind the workspace
            bindWorkspace(-1);
        }
    
    

    WorkSpaceデータのロード
    WorkSpaceデータをロードする方法はすべてloadWorkSpace()にあり、このステップはプロセス全体の最も核心的なものであり、loadWorkSpace()という方法しかありませんが、私の現在のバージョンではこの方法のソースコードは600行以上に達しているので、コアのコードを切り取って分析し、多くの詳細は自分で考えなければなりません.
    
        final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
    
        final Context context = mContext;
        final ContentResolver contentResolver = context.getContentResolver();
        final PackageManager manager = context.getPackageManager();
        final boolean isSafeMode = manager.isSafeMode();
        final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
        final boolean isSdCardReady = context.registerReceiver(null,
                new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;
    
        LauncherAppState app = LauncherAppState.getInstance();
        InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
        int countX = profile.numColumns;
        int countY = profile.numRows;
    
        if (GridSizeMigrationTask.ENABLED &&
                !GridSizeMigrationTask.migrateGridIfNeeded(mContext)) {
            // Migration failed. Clear workspace.
            mFlags = mFlags | LOADER_FLAG_CLEAR_WORKSPACE;
        }
    
        if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {
            Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);
            LauncherAppState.getLauncherProvider().deleteDatabase();
        }
    
        if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {
            // append the user's Launcher2 shortcuts
            Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);
            LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();
        } else {
            // Make sure the default workspace is loaded
            Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);
            LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();
        }
    
    

    まず、ContentResolver、LauncherAppsCompat、LauncherAppState、InvariantDeviceProfileなどのコアオブジェクトについて説明します.最初のif条件は、Lacuncher 2などのデータベース移植について、Launcher 3にアップグレードし、デスクトップアイコンのサイズが変化する特殊な場合の処理であり、特に注意する必要はありません.
    WorkSpaceリソースファイルのロード
    重要なコードはLauncherAppStateです.getLauncherProvider().loadDefaultFavoritesIfNecessary(); Launcherを初めて開くと、デスクトップのトップページに表示されるコンテンツ、hotseat構成など、デフォルトのデータがロードされます.LauncherAppStateコードを見るとLauncherProviderのloadDefaultFavoritesIfNecessaryメソッドが呼び出されていることがわかります
    
        /**
            * Loads the default workspace based on the following priority scheme:
            *   1) From the app restrictions
            *   2) From a package provided by play store
            *   3) From a partner configuration APK, already in the system image
            *   4) The default configuration for the particular device
            */
        synchronized public void loadDefaultFavoritesIfNecessary() {
            SharedPreferences sp = Utilities.getPrefs(getContext());
    
            if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
                Log.d(TAG, "loading default workspace");
    
                AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction();
                if (loader == null) {
                    loader = AutoInstallsLayout.get(getContext(),
                            mOpenHelper.mAppWidgetHost, mOpenHelper);
                }
                if (loader == null) {
                    final Partner partner = Partner.get(getContext().getPackageManager());
                    if (partner != null && partner.hasDefaultLayout()) {
                        final Resources partnerRes = partner.getResources();
                        int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
                                "xml", partner.getPackageName());
                        if (workspaceResId != 0) {
                            loader = new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost,
                                    mOpenHelper, partnerRes, workspaceResId);
                        }
                    }
                }
    
                final boolean usingExternallyProvidedLayout = loader != null;
                if (loader == null) {
                    loader = getDefaultLayoutParser();
                }
    
                // There might be some partially restored DB items, due to buggy restore logic in
                // previous versions of launcher.
                createEmptyDB();
                // Populate favorites table with initial favorites
                if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
                        && usingExternallyProvidedLayout) {
                    // Unable to load external layout. Cleanup and load the internal layout.
                    createEmptyDB();
                    mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
                            getDefaultLayoutParser());
                }
                clearFlagEmptyDbCreated();
            }
        }
    
    

    通常のプロセスでは実行されません.簡単に説明しますが、この方法はコメントと同様に、次の方法のいずれかからデフォルトのレイアウトがロードされます.
  • 制約を適用し、createWorkspaceLoaderFromAppRestrictionを呼び出し、ユーザーが設定したアプリケーション機能を制限するためのBundle列のセットを取得し、Bundle内のworkspaceを取得する.configuration.package.名前の具体的なアプリケーションパッケージ名は、WorkSpaceのデフォルト構成リソースを取得します.
  • はandroidを持っています.autoinstalls.config.action.PLAY_AUTO_INSTALL Actionのアプリケーションでワークスペースのデフォルト構成リソースを取得する
  • システム内蔵パートナアプリケーションからworkspaceデフォルト構成
  • を取得
  • getDefaultLayoutParser()を呼び出して、Launcherのデフォルトリソース
  • を取得します.
    デフォルトのプロセスでは、ステップ4を実行し、データベースを作成し、テーブルfavoritesとworkspaceScreensを構築し、データmOpenHelperをロードします.loadFavorites
    
        private DefaultLayoutParser getDefaultLayoutParser() {
            int defaultLayout = LauncherAppState.getInstance()
                    .getInvariantDeviceProfile().defaultLayoutId;
            return new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost,
                    mOpenHelper, getContext().getResources(), defaultLayout);
        }
    
    
    

    デフォルトのリソースはR.xmlのようなInvariantDeviceProfileを構成するリソースです.default_workspace_5 x 6、詳しくは前の文章を参照してください.したがって、res/xml/でデフォルトの表示アプリケーションの構成を変更することができます.
    
        @Thunk 
        int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
            ArrayList screenIds = new ArrayList();
            // TODO: Use multiple loaders with fall-back and transaction.
            int count = loader.loadLayout(db, screenIds);
    
            // Add the screens specified by the items above
            Collections.sort(screenIds);
            int rank = 0;
            ContentValues values = new ContentValues();
            for (Long id : screenIds) {
                values.clear();
                values.put(LauncherSettings.WorkspaceScreens._ID, id);
                values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank);
                if (dbInsertAndCheck(this, db, TABLE_WORKSPACE_SCREENS, 
                    null, values) < 0) {
                    throw new RuntimeException("Failed initialize screen table"
                            + "from default layout");
                }
                rank++;
            }
    
            // Ensure that the max ids are initialized
            mMaxItemId = initializeMaxItemId(db);
            mMaxScreenId = initializeMaxScreenId(db);
    
            return count;
        }
    
    

    loadFavoritesメソッドでDefaultLayoutParserを呼び出します.loadLayout(db,screenIds)は、レイアウトxmlのフォルダ情報、アプリケーション情報、widget情報などを解析してデータベースに保存し、画面idセットを取得し、workspaceScreensテーブルに保存します.どのように解析するかについては、重要なコードを直接見てみましょう.
    AutoInstallsLayout.java
    
         /**
            * Parses the layout and returns the number of elements added on the homescreen.
            */
        protected int parseLayout(int layoutId, ArrayList screenIds)
                throws XmlPullParserException, IOException {
            XmlResourceParser parser = mSourceRes.getXml(layoutId);
            beginDocument(parser, mRootTag);
            final int depth = parser.getDepth();
            int type;
            HashMap tagParserMap = getLayoutElementsMap();
            int count = 0;
    
            while (((type = parser.next()) != XmlPullParser.END_TAG ||
                    parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
                if (type != XmlPullParser.START_TAG) {
                    continue;
                }
                count += parseAndAddNode(parser, tagParserMap, screenIds);
            }
            return count;
        }
    

    XmlResourceParserでxmlファイルを解析し、必要な構成を取得します.異なるラベルは異なる解析オブジェクトで処理され、AutoInstallsLayoutのサブクラスDefaultLayoutParserを使用しています.getLayoutElementsMap()メソッドでは、解析器ResolveParser、フォルダ解析器MyFolderParserなど、情報を解析して対応するデータベースに保存する処理オブジェクトが表示されます.これがデフォルトワークスペースをロードする原理です.解析の詳細は一つ一つ紹介しません.必要な解析器を見つけてコードを考えてください.
    DefaultLayoutParser.java
    
        @Override
        protected HashMap getLayoutElementsMap() {
            HashMap parsers = new HashMap();
            parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
            parsers.put(TAG_APPWIDGET, new AppWidgetParser());
            parsers.put(TAG_SHORTCUT, new UriShortcutParser(mSourceRes));
            parsers.put(TAG_RESOLVE, new ResolveParser());
            parsers.put(TAG_FOLDER, new MyFolderParser());
            parsers.put(TAG_PARTNER_FOLDER, new PartnerFolderParser());
            return parsers;
        }
    
    

    デフォルトの構成について簡単に説明します.
    default_workspace_4x4.xml
    
    
    
        
        
    
        
        
            
            
        
    
        
            
            
        
    
        
            
            
        
    
    
    
    
  • @xml/dw_phone_hotseat、hotseatプロファイル、構成ルールは同じ
  • resolveラベル、ResolveParser解析により、埋め込みラベル
  • を含む
  • favorite、1つのappの情報、uriを指定することができて、あるいは具体的なパケット名、クラス名はapp
  • を識別します
  • はカスタムラベルがあり、自分で解析を実現すれば
  • である.
    これでloadDefaultFavoritesIfNecessary()が完了し、LauncherModelに戻ってloadWorkspace()を見続けます.
    データの読み込み
    次に、プロファイルから読み込まれた情報をデータベースから読み出し、itemTypeに従ってswitchの異なるcaseを歩きます.
    
        final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
        if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);
        final Cursor c = contentResolver.query(contentUri, null, null, null, null);
    
        // +1 for the hotseat (it can be larger than the workspace)
        // Load workspace in reverse order to ensure that latest items are loaded first (and
        // before any earlier duplicates)
        final LongArrayMap occupied = new LongArrayMap<>();
        HashMap widgetProvidersMap = null;
        ...
        while (!mStopped && c.moveToNext()) {
            try {
                int itemType = c.getInt(itemTypeIndex);
                boolean restored = 0 != c.getInt(restoredIndex);
                boolean allowMissingTarget = false;
                container = c.getInt(containerIndex);
    
                switch (itemType) {
                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                    ...
                    
                    sBgItemsIdMap.put(info.id, info);
                    ...
                    break;
    
                case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                    ...
                    sBgItemsIdMap.put(folderInfo.id, folderInfo);
                    sBgFolders.put(folderInfo.id, folderInfo);
                    ...
                    break;
                case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
                case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
            ...
    
    

    例えばITEM_TYPE_APPLICATIONとITEM_TYPE_SHORTCUT、実行は最後までLongArrayMap sBgItems IdMapに保存されます.そしてITEM_TYPE_FOLDERは、LongArrayMap sBgFoldersに保存するとともに、sBgItemsIdMapにも保存します.FolderInfoとアプリケーションのAppInfoのため、ShortcutInfoはいずれもItemInfoを継承しており、その後は変換処理が可能です.ITEM_TYPE_APPWIDGET,ITEM_TYPE_CUSTOM_APPWIDGETも同じです.
    ここの詳細は比較的多く、通常、ここのクエリーロジックを特に修正する必要はありませんので、詳しく説明しません.
    WorkSpaceデータのバインド
    ワークスペースデータのロードが完了したら、次のようにワークスペースにデータをバインドし、bindWorkspace(-1)メソッドを呼び出します.前回、私はデータがすべて集合sBgWorkspaceItems、sBgAppWidgets、sBgWorkspaceScreensに保存されていることを知っていました.ここでGoogleは直接中のデータを遍歴しているのではなく、Viewにバインドされています.後続のスレッドがグローバル変数を変更して他の作業スレッドに影響を与えないようにcopyの操作を行いました.
            private void bindWorkspace(int synchronizeBindPage) {
                // Save a copy of all the bg-thread collections
                ArrayList workspaceItems = new ArrayList();
                ArrayList appWidgets =
                        new ArrayList();
                ArrayList orderedScreenIds = new ArrayList();
    
                final LongArrayMap folders;
                final LongArrayMap itemsIdMap;
    
                synchronized (sBgLock) {
                    workspaceItems.addAll(sBgWorkspaceItems);
                    appWidgets.addAll(sBgAppWidgets);
                    orderedScreenIds.addAll(sBgWorkspaceScreens);
    
                    folders = sBgFolders.clone();
                    itemsIdMap = sBgItemsIdMap.clone();
                }
    
                final boolean isLoadingSynchronously =
                        synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;
                int currScreen = isLoadingSynchronously ? synchronizeBindPage :
                    oldCallbacks.getCurrentWorkspaceScreen();
                if (currScreen >= orderedScreenIds.size()) {
                    // There may be no workspace screens (just hotseat items and an empty page).
                    currScreen = PagedView.INVALID_RESTORE_PAGE;
                }
                final int currentScreen = currScreen;
                final long currentScreenId = currentScreen < 0
                        ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);
    
                // Load all the items that are on the current page first (and in the process, unbind
                // all the existing workspace items before we call startBinding() below.
                unbindWorkspaceItemsOnMainThread();
    
                // Separate the items that are on the current screen, and all the other remaining items
                ArrayList currentWorkspaceItems = new ArrayList();
                ArrayList otherWorkspaceItems = new ArrayList();
                ArrayList currentAppWidgets =
                        new ArrayList();
                ArrayList otherAppWidgets =
                        new ArrayList();
                LongArrayMap currentFolders = new LongArrayMap<>();
                LongArrayMap otherFolders = new LongArrayMap<>();
    
                filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,
                        otherWorkspaceItems);
                filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,
                        otherAppWidgets);
                filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,
                        otherFolders);
                sortWorkspaceItemsSpatially(currentWorkspaceItems);
                sortWorkspaceItemsSpatially(otherWorkspaceItems);
                // Tell the workspace that we're about to start binding items
                r = new Runnable() {
                    public void run() {
                        Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                        if (callbacks != null) {
                            callbacks.startBinding();
                        }
                    }
                };
                runOnMainThread(r);
                Log.e(TAG, "orderedScreenIds:" + orderedScreenIds);
    

    その後、一連のfilterメソッドとsortメソッドは、現在ロードする必要があるページのデータをscreenIdでソートし、新しいセットに埋め込む.準備は完了し、tryGetCallbackによってCallbackが取得されます.このCallbackはLauncherModelのmCallbackです.初期化はLauncher onCreateでLauncherAppStateを呼び出します.setLauncherは、LauncherModelのinitialize()で付与を完了します.だから、Callbacksは私たちのLauncherです.
    Launcherで実装されているstartBinding()を呼び出し、workspaceの状態を変更し、古いViewとデータを削除します.
        /**
         * Refreshes the shortcuts shown on the workspace.
         * 

    * Implementation of the method from LauncherModel.Callbacks. */ public void startBinding() { setWorkspaceLoading(true); // If we're starting binding all over again, clear any bind calls we'd postponed in // the past (see waitUntilResume) -- we don't need them since we're starting binding // from scratch again mBindOnResumeCallbacks.clear(); // Clear the workspace because it's going to be rebound mWorkspace.clearDropTargets(); mWorkspace.removeAllWorkspaceScreens(); mWidgetsToAdvance.clear(); if (mHotseat != null) { mHotseat.resetLayout(); } }


    次にバインドを開始します
  • ワークスペースをバインドするScreen,bindワークスペースScreens
  • ワークスペースの現在のページをバインドするItems(アプリケーション情報、コンポーネント情報、bindWorkspaceItems
  • を含む)
  • Workspaceの他のページをバインドするItems
  • bindWorkspace(int synchronizeBindPage)    :
    
                bindWorkspaceScreens(oldCallbacks, orderedScreenIds);
    
                // Load items on the current page
                bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,
                        currentFolders, null);
                if (isLoadingSynchronously) {
                    r = new Runnable() {
                        public void run() {
                            Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                            if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {
                                callbacks.onPageBoundSynchronously(currentScreen);
                            }
                        }
                    };
                    runOnMainThread(r);
                }
    
                // Load all the remaining pages (if we are loading synchronously, we want to defer this
                // work until after the first render)
                synchronized (mDeferredBindRunnables) {
                    mDeferredBindRunnables.clear();
                }
                bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,
                        (isLoadingSynchronously ? mDeferredBindRunnables : null));
            
    

    bindWorkspaceScreens、bindWorkspaceItemsで最終的に呼び出されたのはLauncherのコールバック方法、bindScreens、bindItems、bindFoldersなどです.バインドScreenを例に
        @Override
        public void bindScreens(ArrayList orderedScreenIds) {
            bindAddScreens(orderedScreenIds);
    
            // If there are no screens, we need to have an empty screen
            if (orderedScreenIds.size() == 0) {
                mWorkspace.addExtraEmptyScreen();
            }
    
            // Create the custom content page (this call updates mDefaultScreen which calls
            // setCurrentPage() so ensure that all pages are added before calling this).
            if (hasCustomContentToLeft()) {
                mWorkspace.createCustomContentContainer();
                populateCustomContentContainer();
            }
        }
    
        @Override
        public void bindAddScreens(ArrayList orderedScreenIds) {
            int count = orderedScreenIds.size();
            for (int i = 0; i < count; i++) {
         mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(orderedScreenIds.get(i));
            }
        }
    
    

    Screen Idコレクションを取得し、Workspaceのi n s e r t NewWorkspaceScreenBeforeEmptyScreenを呼び出し、対応するCellLayoutを作成し、私たちのWorkspaceというコンテナに追加します.
    
        public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {
            // Find the index to insert this view into.  If the empty screen exists, then
            // insert it before that.
            int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
            if (insertIndex < 0) {
                insertIndex = mScreenOrder.size();
            }
            return insertNewWorkspaceScreen(screenId, insertIndex);
        }
    
    
        public long insertNewWorkspaceScreen(long screenId, int insertIndex) {
            if (mWorkspaceScreens.containsKey(screenId)) {
                throw new RuntimeException("Screen id " + screenId + " already exists!");
            }
    
            // Inflate the cell layout, but do not add it automatically so that we can get the newly
            // created CellLayout.
            CellLayout newScreen = (CellLayout) mLauncher.getLayoutInflater().inflate(
                            R.layout.workspace_screen, this, false /* attachToRoot */);
    
            newScreen.setOnLongClickListener(mLongClickListener);
            newScreen.setOnClickListener(mLauncher);
            newScreen.setSoundEffectsEnabled(false);
            mWorkspaceScreens.put(screenId, newScreen);
            mScreenOrder.add(insertIndex, screenId);
            addView(newScreen, insertIndex);
    
            LauncherAccessibilityDelegate delegate =
                    LauncherAppState.getInstance().getAccessibilityDelegate();
            if (delegate != null && delegate.isInAccessibleDrag()) {
                newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
            }
            return screenId;
        }
    
    

    アイコン、フォルダ、コンポーネントの作成プロセスは似ていますが、似たようなものは繰り返しません.具体的な詳細は皆さんがゆっくり考えなければなりません.
    すべてのアプリケーションをロード
    ワークスペースをロードすると、すべてのアプリケーションがロードされ、アプリケーションアイコンが更新されます.
        private void loadAndBindAllApps() {
            if (DEBUG_LOADERS) {
                Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
            }
            if (!mAllAppsLoaded) {
                loadAllApps();
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return;
                    }
                }
                updateIconCache();
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return;
                    }
                    mAllAppsLoaded = true;
                }
            } else {
                onlyBindAllApps();
            }
        }
    
    

    すべてのアプリケーションをロードし、mBgAllAppsList AllAppsListオブジェクトに保存します.
    
        private void loadAllApps() {
            final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
    
            final Callbacks oldCallbacks = mCallbacks.get();
            if (oldCallbacks == null) {
                // This launcher has exited and nobody bothered to tell us.  Just bail.
                Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");
                return;
            }
    
            final List profiles = mUserManager.getUserProfiles();
    
            // Clear the list of apps
            mBgAllAppsList.clear();
            for (UserHandleCompat user : profiles) {
                // Query for the set of apps
                final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                final List apps = mLauncherApps.getActivityList(null, user);
                if (DEBUG_LOADERS) {
                    Log.d(TAG, "getActivityList took "
                            + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
                    Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
                }
                // Fail if we don't have any apps
                // TODO: Fix this. Only fail for the current user.
                if (apps == null || apps.isEmpty()) {
                    return;
                }
                boolean quietMode = mUserManager.isQuietModeEnabled(user);
                // Create the ApplicationInfos
                for (int i = 0; i < apps.size(); i++) {
                    LauncherActivityInfoCompat app = apps.get(i);
                    // This builds the icon bitmaps.
                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, quietMode));
                }
    
                final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);
                if (heuristic != null) {
                    final Runnable r = new Runnable() {
    
                        @Override
                        public void run() {
                            heuristic.processUserApps(apps);
                        }
                    };
                    runOnMainThread(new Runnable() {
    
                        @Override
                        public void run() {
                            // Check isLoadingWorkspace on the UI thread, as it is updated on
                            // the UI thread.
                            if (mIsLoadingAndBindingWorkspace) {
                                synchronized (mBindCompleteRunnables) {
                                    mBindCompleteRunnables.add(r);
                                }
                            } else {
                                runOnWorkerThread(r);
                            }
                        }
                    });
                }
            }
            // Huh? Shouldn't this be inside the Runnable below?
            final ArrayList added = mBgAllAppsList.added;
            mBgAllAppsList.added = new ArrayList();
    
            // Post callback on main thread
            mHandler.post(new Runnable() {
                public void run() {
    
                    final long bindTime = SystemClock.uptimeMillis();
                    final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                    if (callbacks != null) {
                        callbacks.bindAllApplications(added);
                        if (DEBUG_LOADERS) {
                            Log.d(TAG, "bound " + added.size() + " apps in "
                                    + (SystemClock.uptimeMillis() - bindTime) + "ms");
                        }
                    } else {
                        Log.i(TAG, "not binding apps: no Launcher activity");
                    }
                }
            });
            // Cleanup any data stored for a deleted user.
            ManagedProfileHeuristic.processAllUsers(profiles, mContext);
            if (DEBUG_LOADERS) {
                Log.d(TAG, "Icons processed in "
                        + (SystemClock.uptimeMillis() - loadTime) + "ms");
            }
        }
    
    

    LauncherAppsCompatのオブジェクトを通して、すべてのインストールされたアプリケーションを入手し、AllAppsListに遍歴して追加します.
        mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, quietMode));
        
    

    ワークスペースデータのバインドと同様に、Launcherで実装されたコールバックメソッドbindAllApplicationsが呼び出され、引き出しViewコンテナにデータが埋め込まれます.
        /**
         * Add the icons for all apps.
         * 

    * Implementation of the method from LauncherModel.Callbacks. */ public void bindAllApplications(final ArrayList apps) { if (waitUntilResume(mBindAllApplicationsRunnable, true)) { mTmpAppsList = apps; return; } if (mAppsView != null) { mAppsView.setApps(apps); } if (mLauncherCallbacks != null) { mLauncherCallbacks.bindAllApplications(apps); } }


    これでロードプロセスは基本的に終了します.みんなに1つの大まかな流れを整理して、多くの细かい点はすべて绍介していないで、分からない地方は伝言を残すことができて、ありがとうございます.