【源码剖析】Launcher 8.0 源码 (12) --- Launcher 启动流程 第六步之简述

Launcher8.0启动流程的第六步生成布局,Launcher启动流程中最重要,最复杂,也是网上各种关于Launcher讲解的最浓墨淡彩描述的部分。

第六步onCreate中源码如下:

 if (!mModel.startLoader(currentScreen)) {
        mDragLayer.setAlpha(0);
    } else {
        mWorkspace.setCurrentPage(currentScreen);
        setWorkspaceLoading(true);
    }

 

那么最关键的一行代码是mModel.startLoader(currentScreen)。这代码是让LauncherModel开始读取应用的。包括桌面的布局和allapp的应用,将所有应用和图标放到之前我们规划好的几行几列的格子里面。返回false表示读取失败,这时候会走mDragLayer.setAlpha(0),如果布局读取失败则将整个mDragLayer都不显示也就是桌面一片空白,而正常情况都是读取成功

 

于是重点就是mModel.startLoader(currentScreen)此方法。

startLoader的源码如下:

 

public boolean startLoader(int synchronousBindPage) {
    InstallShortcutReceiver.enableInstallQueue();
    synchronized (mLock) {
            mLoaderTask = new LoaderTask(mApp.getContext(), synchronousBindPage);
            if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
                    && mModelLoaded && !mIsLoaderTaskRunning) {
                mLoaderTask.runBindSynchronousPage(synchronousBindPage);
                return true;
            } else {
                sWorkerThread.setPriority(Thread.NORM_PRIORITY);
                sWorker.post(mLoaderTask);
            }
        }
    }
    return false;
}

 

从简化的源码,看到关键是有一个mLoaderTask = new LoaderTask(mApp.getContext(), synchronousBindPage);

这里mModelLoaded等进行了一个判断,根据判断结果,我们选择mLoaderTask 的两条分支

If为ture:我们使用runBindSynchronousPage方法

mLoaderTask.runBindSynchronousPage(synchronousBindPage);

If为false:我们使用run方法。

 sWorker.post(mLoaderTask);

含义mModelLoaded为ture表示已经完成了数据库读取,只需要刷新。

runBindSynchronousPage的核心行为对应3个,关键词是bind即将图标数据放到桌面上。

void runBindSynchronousPage(int synchronousBindPage){

bindWorkspace(synchronousBindPage);
onlyBindAllApps();
bindDeepShortcuts();

}

 

而run的方法则更加完整,包含load和bind源码如下:

public void run() {
    synchronized (mLock) {
        if (mStopped) {
            return;
        }
        mIsLoaderTaskRunning = true;
    }

    try {
        if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
        // Set to false in bindWorkspace()
        mIsLoadingAndBindingWorkspace = true;
        loadWorkspace();

        verifyNotStopped();
        if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace");
        bindWorkspace(mPageToBindFirst);

        // Take a break
        if (DEBUG_LOADERS) Log.d(TAG, "step 1 completed, wait for idle");
        waitForIdle();
        verifyNotStopped();

        // second step
        if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps");
        loadAllApps();

        verifyNotStopped();
        if (DEBUG_LOADERS) Log.d(TAG, "step 2.2: Update icon cache");
        updateIconCache();

        // Take a break
        if (DEBUG_LOADERS) Log.d(TAG, "step 2 completed, wait for idle");
        waitForIdle();
        verifyNotStopped();

        // third step
        if (DEBUG_LOADERS) Log.d(TAG, "step 3.1: loading deep shortcuts");
        loadDeepShortcuts();

        verifyNotStopped();
        if (DEBUG_LOADERS) Log.d(TAG, "step 3.2: bind deep shortcuts");
        bindDeepShortcuts();

        // Take a break
        if (DEBUG_LOADERS) Log.d(TAG, "step 3 completed, wait for idle");
        waitForIdle();
        verifyNotStopped();

        // fourth step
        if (DEBUG_LOADERS) Log.d(TAG, "step 4.1: loading widgets");
        refreshAndBindWidgetsAndShortcuts(getCallback(), false /* bindFirst */,
                null /* packageUser */);

        synchronized (mLock) {
            // Everything loaded bind the data.
            mModelLoaded = true;
            mHasLoaderCompletedOnce = true;
        }
    } catch (CancellationException e) {
      // Loader stopped, ignore
    } finally {
        // Clear out this reference, otherwise we end up holding it until all of the
        // callback runnables are done.
        mContext = null;

        synchronized (mLock) {
            // If we are still the last one to be scheduled, remove ourselves.
            if (mLoaderTask == this) {
                mLoaderTask = null;
            }
            mIsLoaderTaskRunning = false;
            updateUnreadNumberAfterLoaded();
        }
    }
}

 

简化后重点管锥这几个方法:

public void run() {
     loadWorkspace();
     bindWorkspace(mPageToBindFirst);
     loadAllApps();
}

 

其中loadAllApps()方法中,包含load的方法和bindAllApplications方法

onlyBindAllApps主要是bindAllApplications方法。

 

也就是run方法和runBindSynchronousPage方法,区别在于是否需要load。

Load方法就是将手机或数据库的对应参数存到缓存(集合)中。

 

由于load和bind  workspace、load和bind  allapp很重要,因此第六步重点关注。

分别是loadworkspace、bindworkspace、load&bind allapp 。

 

第六步行为是通过启动在LauncherModel的多线程,完成对桌面和allapp的图标(包括快捷方式,folder,widegt)的读取和显示。

 

你可能感兴趣的:(源码剖析)