Launcher3 开机后应用数据的加载流程分析

以下是Launcher3从开机后应用图标的一个加载流程的大致的分析:

系统开机开启Launcher3后,执行Launcher3的onCreate()函数,进行应用数据的加载(主要显示的是核心代码):
位置:Launcher.java
if (!mRestoring) {
            if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE
                    || sPausedFromUserAction) {
                // If the user leaves launcher, then we should just load items
                // asynchronously when
                // they return.
                Log.i("Garment05", "Launcher---startLoader111111");
                mModel.startLoader(true, PagedView.INVALID_RESTORE_PAGE);
            } else {
                // We only load the page synchronously if the user rotates (or
                // triggers a
                // configuration change) while launcher is in the foreground
                Log.i("Garment05", "Launcher---startLoader222222");
                mModel.startLoader(true, mWorkspace.getRestorePage());
            }
        }
加载数据主要是调用LauncherModel中的startLoader()方法,具体实现查看其源码:
位置:LauncherModel.java:
public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {
        synchronized (mLock) {
            if (DEBUG_LOADERS) {
                Log.d(TAG, "startLoader isLaunching=" + isLaunching);
            }
            Log.i("Garment05", "LauncherModel---startLoader");

            // Clear any deferred bind-runnables from the synchronized load process
            // We must do this before any loading/binding is scheduled below.
            mDeferredBindRunnables.clear();

            // Don't bother to start the thread if we know it's not going to do anything
            if (mCallbacks != null && mCallbacks.get() != null) {
                // If there is already one running, tell it to stop.
                // also, don't downgrade isLaunching if we're already running
                isLaunching = isLaunching || stopLoaderLocked();
                mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);
                if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
                        && mAllAppsLoaded && mWorkspaceLoaded) {
                    Log.i("Garment05", "LauncherModel---runBindSynchronousPage");
                    mLoaderTask.runBindSynchronousPage(synchronousBindPage);   //转屏时执行
                } else {
                    Log.i("Garment05", "LauncherModel---post");
                    sWorkerThread.setPriority(Thread.NORM_PRIORITY);
                    sWorker.post(mLoaderTask);         //数据需要重新加载时执行,例如开机重启。
                }
            }
        }
    }
startLoader()函数的核心代码是线程类LoaderTask,该类中有两条路径进行应用数据的加载,其中一个路径是runBindSynchronousPage(),这个方法作用是重新绑定桌面的应用。第二种路径是LoaderTask线程类的run()方法。该方法的具体实现代码:
位置:LauncherModel.java:
public void run() {
            boolean isUpgrade = false;

            synchronized (mLock) {
                mIsLoaderTaskRunning = true;
            }
            // Optimize for end-user experience: if the Launcher is up and // running with the
            // All Apps interface in the foreground, load All Apps first. Otherwise, load the
            // workspace first (default).
            keep_running: {
                // Elevate priority when Home launches for the first time to avoid
                // starving at boot time. Staring at a blank home is not cool.
                synchronized (mLock) {
                    if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +
                            (mIsLaunching ? "DEFAULT" : "BACKGROUND"));
                    android.os.Process.setThreadPriority(mIsLaunching
                            ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
                }
                if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
                Log.i("Garment05", "LauncherModel---step1:loading workspace");
                isUpgrade = loadAndBindWorkspace();

                if (mStopped) {
                    break keep_running;
                }

                // Whew! Hard work done.  Slow us down, and wait until the UI thread has
                // settled down.
                synchronized (mLock) {
                    if (mIsLaunching) {
                        if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");
                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    }
                }
                waitForIdle();

                // second step
                if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
                Log.i("Garment05", "LauncherModel---step2:loading all apps");
                loadAndBindAllApps();

                // Restore the default thread priority after we are done loading items
                synchronized (mLock) {
                    android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                }
            }
在run()方法中,先是执行loadAndBindWorkspace()方法进行workspace的加载,然后执行loadAndBindAllApps()方法进行所有的app的加载。

*************************先进行loadAndBindWorkspace()的分析 start*****************:
位置:LauncherModel.java:
private boolean loadAndBindWorkspace() {
            mIsLoadingAndBindingWorkspace = true;
                Log.i("Garment05", "LauncherModel---loadAndBindWorkspace");
            // Load the workspace
            if (DEBUG_LOADERS) {
                Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);
            }

            boolean isUpgradePath = false;
            //disable by Garment
//            if (!mWorkspaceLoaded) {
                Log.i("Garment05", "Launcher---!mWorkspaceLoaded--loadWorkspace");
                isUpgradePath = loadWorkspace();
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return isUpgradePath;
                    }
                    mWorkspaceLoaded = true;
                }
//            }


            // Bind the workspace
            bindWorkspace(-1, isUpgradePath);
            return isUpgradePath;
        }
loadAndBindWorkspace()中,先是执行loadWorkspace()方法进行workspace中的应用信息的加载(从数据库中加载),然后执行bindWorkspace()方法将应用信息绑定到workspace中。
先查看loadWorkspace()的方法,由于方法比较长,只列出重要的代码:
位置:LauncherModel.java:
loadWorkspace(){

    final Cursor c = contentResolver.query(contentUri, null, null, null, null);
    info.id = id;
    info.intent = intent;
    container = c.getInt(containerIndex);
    info.container = container;
    info.screenId = c.getInt(screenIndex);
    info.cellX = c.getInt(cellXIndex);
    info.cellY = c.getInt(cellYIndex);
    info.spanX = 1;
    info.spanY = 1;
    case LauncherSettings.Favorites.CONTAINER_DESKTOP:
    case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
         sBgWorkspaceItems.add(info);
    break;                                   
}
loadWorkspace()方法中,先是从数据库中查询所有的应用信息,然后生成一个shortcutInfo对象,添加到sBgWorkspaceItems列表中,该列表在后面bindWorkspace()方法中会被用到。
再看bindWorkspace()方法,该方法将数据绑定到workspace中(主要列出核心代码部分):
位置:LauncherModel.java:
bindWorkspace(){
            ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();  //该列表保存的是所有显示到workspace的应用的信息
synchronized (sBgLock) {
                workspaceItems.addAll(sBgWorkspaceItems);    //sBgWorkspaceItems是在上一个loadWorkspace()方法中保存的所有的应用的信息,把它全部添加到
                                                            //workspaceItems这个列表中
                appWidgets.addAll(sBgAppWidgets);
                folders.putAll(sBgFolders);
                itemsIdMap.putAll(sBgItemsIdMap);
                orderedScreenIds.addAll(sBgWorkspaceScreens);
            }
            ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();//保存的是当前页的workspace的应用信息
            ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();   //保存的是其他页的workspace的应用信息
filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,otherWorkspaceItems);//筛选信息保存到currentWorkspaceItems,    
                                                                                    //otherWorkspaceItems两个列表中。
bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, currentFolders, null);//绑定属于当前workspace的元素到workspace中
bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders, (isLoadingSynchronously ? mDeferredBindRunnables : null));                                                                               //绑定属于其他workspace的元素到workspace中

}

*************************loadAndBindWorkspace()的分析 end********************

*************************然后进行loadAndBindAllApps()的分析 start*****************:
位置:LauncherModel.java:
private void loadAndBindAllApps() {
            Log.i("Garment05", "LauncherModel---loadAndBindAllApps()");
            if (DEBUG_LOADERS) {
                Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
            }
            //disable by Garment
//            if (!mAllAppsLoaded) {
                Log.i("Garment05", "LauncherModel---loadAllApps()");
                loadAllApps();
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return;
                    }
                    mAllAppsLoaded = true;
                }
//            } else {
//                Log.i("Garment05", "LauncherModel---onlyBindAllApps()");
//                onlyBindAllApps();
//            }
        }
在该方法中,如果应用没有被加载,则执行loadAllApps()方法进行应用的重新加载,否则只是执行onlyBindAllApps()方法进行应用的绑定。
主要分析loadAllApps()的方法:
位置:LauncherModel.java:
loadAllApps(){

 final PackageManager packageManager = mContext.getPackageManager();
            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

            // Clear the list of apps
            mBgAllAppsList.clear();

            // Query for the set of apps
            final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
            List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);//系统中查询该类型的intent的所有的app
            if (DEBUG_LOADERS) {
                Log.d(TAG, "queryIntentActivities took "
                        + (SystemClock.uptimeMillis()-qiaTime) + "ms");
                Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");
            }
            // Fail if we don't have any apps
            if (apps == null || apps.isEmpty()) {
                return;
            }
            // Sort the applications by name
            final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
            Collections.sort(apps,
                    new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
            if (DEBUG_LOADERS) {
                Log.d(TAG, "sort took "
                        + (SystemClock.uptimeMillis()-sortTime) + "ms");
            }

            // Create the ApplicationInfos
            for (int i = 0; i < apps.size(); i++) {
                ResolveInfo app = apps.get(i);
                // This builds the icon bitmaps.
                mBgAllAppsList.add(new AppInfo(packageManager, app,             //所有的应用生成AppInfo并添加到mBgAllAppsList列表中
                        mIconCache, mLabelCache));
            }

            // Huh? Shouldn't this be inside the Runnable below?
            final ArrayList<AppInfo> added = mBgAllAppsList.added;          //获取所有的已经添加的应用的信息到added列表中             
            mBgAllAppsList.added = new ArrayList<AppInfo>();

            // 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");
                    }
                }
            });

}
该方法获取所有的应用的信息,最后调用bindAllApplications(added)接口把应用的信息绑定到Launcher中,该接口的实现是在Launcher.java中
位置:Launcher.java
public void bindAllApplications(final ArrayList<AppInfo> apps) {
        if (LauncherAppState.isDisableAllApps()) {
            if (mIntentsOnWorkspaceFromUpgradePath != null) {
                if (LauncherModel.UPGRADE_USE_MORE_APPS_FOLDER) {
                    getHotseat().addAllAppsFolder(mIconCache,
                            apps, //
                            mIntentsOnWorkspaceFromUpgradePath, Launcher.this,
                            mWorkspace);
                }
                mIntentsOnWorkspaceFromUpgradePath = null;
            }
            if (mAppsCustomizeContent != null) {
                mAppsCustomizeContent.onPackagesUpdated(LauncherModel
                        .getSortedWidgetsAndShortcuts(this));
            }
        } else {
            if (mAppsCustomizeContent != null) {
                mAppsCustomizeContent.setApps(apps);
                mAppsCustomizeContent.onPackagesUpdated(LauncherModel
                        .getSortedWidgetsAndShortcuts(this));
            }
        }
    }
*************************loadAndBindAllApps()的分析 end*****************:
最终应用的信息添加到Launcher中。具体如何显示到Launcher中,就要具体分析workspace的数据加载部分和allapplist的数据加载部分。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值