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类中是怎样实现具体的回调方法的,会在后面进行讨论。


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