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)的读取和显示。