Launcher2 Analysis - Loading and Binding AllApp List

Previous related blog: Launcher2 Analysis - Loading Workspace Data and Binding

The view of the Android application list is in the launcher.xml, which means that the application list view has been loaded at the beginning, but it is not displayed. The attribute is invisible, and it is in the same viewgroup as the Workspace. The id is apps_customize_pane, the actual type is com.android.launcher2.AppsCustomizeTabHost, which inherits from TabHost, and the layout apps_customize_pane.xml contains a child whose id is apps_customize_pane_content and the type is AppsCustomizePagedView, which indirectly inherits PagedView and is the core of the application list view.

<include layout="@layout/apps_customize_pane"
            android:id="@+id/apps_customize_pane"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="invisible" />

Start analyzing from LauncherModel$LoaderTask#loadAndBindApps():

private void loadAndBindAllApps() {
            if (DEBUG_LOADERS) {
                Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
            }
            if (!mAllAppsLoaded) {//Determine whether all apps have been loaded
                loadAllAppsByBatch();//Load all app information and bind in batches
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return;
                    }
                    mAllAppsLoaded = true;
                }
            } else {
                onlyBindAllApps();//Skip the loading process and bind directly
            }
        }

Analyze loadAllAppsByBatch():

private void loadAllAppsByBatch() {
            final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

            // Don't use these two variables in any of the callback runnables.
            // Otherwise we hold a reference to them.
            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 (loadAllAppsByBatch)");
                return;
            }

            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);//The action needs to be main
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);//The category also needs to be the launcher
//Related to linux multi-users, there are as many UserHandles as there are users, but generally there is only one mobile phone
            final List<UserHandle> profiles = mUserManager.getUserProfiles();

            mBgAllAppsList.clear();
            final int profileCount = profiles.size();
            for (int p = 0; p < profileCount; p++) {
                UserHandle user = profiles.get(p);
                List<LauncherActivityInfo> apps = null;
                int N = Integer.MAX_VALUE;//This is just the initialization, it will be changed later

                int startIndex;
                int i = 0;
                int batchSize = -1;
                while (i < N && !mStopped) {//N为apps的size
                    if (i == 0) {
                        final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                        apps = mLauncherApps.getActivityList(null, user);//Get all apps of the corresponding user
                        if (DEBUG_LOADERS) {
                            Log.d(TAG, "queryIntentActivities took "
                                    + (SystemClock.uptimeMillis()-qiaTime) + "ms");
                        }
                        if (apps == null) {
                            return;
                        }
                        N = apps.size();//Reassign to N here, not the max value of Integer
                        if (DEBUG_LOADERS) {
                            Log.d(TAG, "queryIntentActivities got " + N + " apps");
                        }
                        if (N == 0) {
                            // There are no apps?!?
                            return;
                        }
                        if (mBatchSize == 0) {
                            batchSize = N;
                        } else {
                            batchSize = mBatchSize;//Set how to batch and how many applications there are in a batch. It should be that too many batches may cause anr, causing other events to not be responded to in time
                        }

                        final long sortTime = DEBUG_LOADERS? SystemClock.uptimeMillis (): 0;
                        Collections.sort(apps,
                                new LauncherModel.ShortcutNameComparator(mLabelCache));//Reorder apps
                        if (DEBUG_LOADERS) {
                            Log.d(TAG, "sort took "
                                    + (SystemClock.uptimeMillis () - sortTime) + "ms");
                        }
                    }

                    final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

                    startIndex = i;
                    for (int j=0; i<N && j<batchSize; j++) {//Under the action of the outer while loop, the content in the for will be cycled N times
                        // This builds the icon bitmaps.
                        mBgAllAppsList.add(new ApplicationInfo(apps.get(i), user,
                                mIconCache, mLabelCache));//mBgAllAppsList is not a List, but a class that encapsulates a List, which will be analyzed later
                        i++;
                    }

                    final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                    final ArrayList<ApplicationInfo> added = mBgAllAppsList.added;//Send the added reference object
                    final boolean firstProfile = p == 0;
                    mBgAllAppsList.added = new ArrayList<ApplicationInfo>();//Point the added member to the new object, because this time it is new, so it will not be the next time
                    mHandler.post(new Runnable() {
                        public void run() {
                            final long t = SystemClock.uptimeMillis();
                            if (callbacks != null) {
                                if (firstProfile) {//firstProfile should represent the root user, all apps need to be loaded
                                    callbacks.bindAllApplications(added);//This method will be analyzed later
                                } else {
                                    callbacks.bindAppsAdded(added);//If it is another user, only the new content will be loaded
                                }
                                if (DEBUG_LOADERS) {
                                    Log.d(TAG, "bound " + added.size() + " apps in "
                                        + (SystemClock.uptimeMillis() - t) + "ms");
                                }
                            } else {
                                Log.i(TAG, "not binding apps: no Launcher activity");
                            }
                        }
                    });

                    if (DEBUG_LOADERS) {
                        Log.d(TAG, "batch of " + (i-startIndex) + " icons processed in "
                                + (SystemClock.uptimeMillis()-t2) + "ms");
                    }

                    if (mAllAppsLoadDelay > 0 && i < N) {
                        try {
                            if (DEBUG_LOADERS) {
                                Log.d(TAG, "sleeping for " + mAllAppsLoadDelay + "ms");
                            }
                            Thread.sleep(mAllAppsLoadDelay);//After each batch of app binding tasks is handed over to the queue of the main thread, it needs to sleep for a period of time before putting the next batch of tasks into the queue
                        } catch (InterruptedException exc) { }
                    }
                }

                if (DEBUG_LOADERS) {
                    Log.d(TAG, "cached all " + N + " apps in "
                            + (SystemClock.uptimeMillis()-t) + "ms"
                            + (mAllAppsLoadDelay > 0 ? " (including delay)" : ""));
                }
            }
        }

Analyze mBgAllAppsList.add(new ApplicationInfo(apps.get(i), user, mIconCache, mLabelCache)); where mBgAllAppsList is the AllAppsList type, and the source code of the add method is as follows:

public void add(ApplicationInfo info) {
        if (findActivity(data, info.componentName, info.user)) {//When this component already exists for the corresponding user, it will not be added to data and added
            return;
        }
        data.add(info);//Add to data to store all apps
        added.add(info);//Add to added, store the new app compared to the last load
    }

Launcher implements the Callback of LauncherModel, the following analysis Launcher#bindAllApplications()

public void bindAllApplications(final ArrayList<ApplicationInfo> apps) {
        Runnable setAllAppsRunnable = new Runnable() {
            public void run() {
                if (mAppsCustomizeContent != null) {

//This mAppsCustomizeContent is the AppsCustomizePagedView type object mentioned at the beginning. After calling the setApps method, the view will be redrawn.

 mAppsCustomizeContent.setApps(apps); } } };
// Remove the progress bar entirely; we could also make it GONE
// but better to remove it since we know it's not going to be used
View progressBar = mAppsCustomizeTabHost. findViewById(R.id.apps_customize_progress_bar);
if (progressBar != null) {
((ViewGroup)progressBar.getParent()).removeView(progressBar);
// We just post the call to setApps so the user sees the progress bar
// disappear-- otherwise, it just looks like the progress bar froze
// which doesn't look great
mAppsCustomizeTabHost.post(setAllAppsRunnable);//It will be posted to the message queue after the progressbar disappears
} else {
// If we did not initialize the spinner in onCreate, then we can directly set the
// list of applications without waiting for any progress bars views to be hidden.
setAllAppsRunnable.run(); }
 }


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326084833&siteId=291194637