Launcher3源碼分析 — 所有應用頁面的數據加載和綁定

加載完workspace的數據後,接下來就開始加載所有應用界面的數據了。通過LauncherModel.loadAndBindAllApps()完成所有應用界面的加載過程,代碼如下:

        private void loadAndBindAllApps() {
            if (!mAllAppsLoaded) {
                loadAllApps();
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return;
                    }
                    mAllAppsLoaded = true;
                }
            } else {
                onlyBindAllApps();
            }
        }
以上代碼分兩種情況,如下圖:



情況一:數據還未加載時,執行loadAllApps(),不要被它的方法名所誤導,該方法實際上完成了load和bind的操作,代碼如下:

         private void loadAllApps() {
            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 PackageManager packageManager = mContext.getPackageManager();
            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

            // mBgAllAppsList是AllAppsList類的引用,裏面維護了4個
            // 列表(data, added, removed, modified),獲取到的所有
            // 應用數據添加到該列表中,加載前先清楚之前的數據
            mBgAllAppsList.clear();

            // 返回所有應用的ResolveInfo列表
            List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
            // Fail if we don't have any apps
            if (apps == null || apps.isEmpty()) {
                return;
            }
            // Sort the applications by name
            Collections.sort(apps,
                    new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));

            // Create the ApplicationInfos
            for (int i = 0; i < apps.size(); i++) {
                ResolveInfo app = apps.get(i);
                // new一個AppInfo,獲取對應的icon和title,mBgAllAppsList.add(AppInfo info)
                // 會把info添加到AllAppList的added和data列表中
                mBgAllAppsList.add(new AppInfo(packageManager, app,
                        mIconCache, mLabelCache));
            }

            // 下面的過程將把added列表與界面綁定,並清空added列表
            final ArrayList<AppInfo> added = mBgAllAppsList.added;
            mBgAllAppsList.added = new ArrayList<AppInfo>();
            mHandler.post(new Runnable() {
                public void run() {
                    final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                    if (callbacks != null) {
                        callbacks.bindAllApplications(added);
                    }
                }
            });
        }


情況二:數據已加載到內存中,執行onlyBindAllApps(),bind操作需要在main thread中執行,代碼如下:
private void onlyBindAllApps() {
    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 (onlyBindAllApps)");
        return;
    }


    // shallow copy,因爲mBgAllAppsList只在worker thread中被訪問,
    // 而bind操作是在main thread中執行的,所以需要進行此copy操作
    @SuppressWarnings("unchecked")
    final ArrayList<AppInfo> list
            = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();
    Runnable r = new Runnable() {
        public void run() {
            final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
            if (callbacks != null) {
                callbacks.bindAllApplications(list);
            }
        }
    };
    // 在main thread中執行bind操作
    boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());
    if (isRunningOnMainThread) {
        r.run();
    } else {
        mHandler.post(r);
    }
}

這樣數據的加載和綁定過程就結束了,至於在Launcher類中是怎樣實現具體的回調方法的,會在後面進行討論。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章