通过调用LoaderTask#startLoader()数据加载和绑定,该方法在Launcher#oncreate()中被调用:
if (sPausedFromUserAction) {
// If the user leaves launcher, then we should just load items asynchronously when
// they return.
mModel.startLoader(true, -1);
} else {
// We only load the page synchronously if the user rotates (or triggers a
// configuration change) while launcher is in the foreground
mModel.startLoader(true, mWorkspace.getCurrentPage());
}
其中第二个参数不为-1时,是同步加载,只有桌面正在显示且屏幕发生旋转时才会同步加载。
看startLoader()这个方法源码:
public void startLoader(boolean isLaunching, int synchronousBindPage) {
synchronized (mLock) {
if (DEBUG_LOADERS) {
Log.d(TAG, "startLoader isLaunching=" + isLaunching);
}
// 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, isLaunching);
if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {
mLoaderTask.runBindSynchronousPage(synchronousBindPage);//同步加载时调用runBindSynchronousPage,而不是run()
} else {
sWorkerThread.setPriority(Thread.NORM_PRIORITY);
sWorker.post(mLoaderTask);//异步加载,在给线程池运行LoaderTask的run()
}
}
}
}
下面来分析异步加载时的数据加载和绑定过程。
数据加载
LauncherModel$LoaderTask#run()
public void run() {
synchronized (mLock) {
mIsLoaderTaskRunning = true;
}
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.
//... ...
// First step. Load workspace first, this is necessary since adding of apps from
// managed profile in all apps is deferred until onResume. See http://b/17336902.
if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
loadAndBindWorkspace();//加载桌面数据和绑定
if (mStopped) {
break keep_running;//在onStop调用后跳出循环
}
// Whew! Hard work done. Slow us down, and wait until the UI thread has
// settled down.
//... ...
waitForIdle();
// Second step. Load all apps.
if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
loadAndBindAllApps();加载应用列表数据和绑定
// Restore the default thread priority after we are done loading items
//... ...
}
// Update the saved icons if necessary
//... ...
// 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;
}
}
其中loadAndBindWorkspace会调用loadWorkspace()和bindWorkspace(),下面先分析loadWorkspace()。
LauncherModel$LoaderTask#loadWorkspace():
1. mApp.getLauncherProvider().loadDefaultFavoritesIfNecessary(0, false);
从xml文件填充数据库favorite表,如果没有填充过。默认是default_workspace.xml,源码如下:
/**
* @param workspaceResId that can be 0 to use default or non-zero for specific resource
*/
synchronized public void loadDefaultFavoritesIfNecessary(int origWorkspaceResId,
boolean overridePrevious) {
String spKey = LauncherApplication.getSharedPreferencesKey();
SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
//如果manifest中没有写上对应的键值对,那么resId返回0
int restrictionLayoutId = getWorkspaceLayoutIdFromAppRestrictions();
boolean restrictionLayoutChanged = didRestrictionLayoutChange(sp, restrictionLayoutId);
overridePrevious |= restrictionLayoutChanged;
boolean dbCreatedNoWorkspace =
sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false);
if (dbCreatedNoWorkspace || overridePrevious) {//如果需要初始化favorite表,进入
SharedPreferences.Editor editor = sp.edit();
// First try layout from app restrictions if it was found
int workspaceResId = restrictionLayoutId;
// If the restrictions are not set, use the resource passed to this method
if (workspaceResId == 0) {//如果restrictionLayoutId为0,就使用调用方法传进来的resId
workspaceResId = origWorkspaceResId;
}
// Use default workspace resource if none provided
if (workspaceResId == 0) {//如果调用返回传进来的resId为0,去sharedpreference拿,默认是default_workspace
workspaceResId = sp.getInt(DEFAULT_WORKSPACE_RESOURCE_ID, R.xml.default_workspace);
} else {
editor.putInt(DEFAULT_WORKSPACE_RESOURCE_ID, workspaceResId);
}
// Populate favorites table with initial favorites
editor.remove(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED);
if (!dbCreatedNoWorkspace && overridePrevious) {
if (LOGD) Log.d(TAG, "Clearing old launcher database");
// Workspace has already been loaded, clear the database.
deleteDatabase();
}
mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), workspaceResId);//将xml中的内容写到数据库
editor.commit();
}
}
default_workspace