以下是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
workspaceItems = new ArrayList(); //该列表保存的是所有显示到workspace的应用的信息
synchronized (sBgLock) {
workspaceItems.addAll(sBgWorkspaceItems); //sBgWorkspaceItems是在上一个loadWorkspace()方法中保存的所有的应用的信息,把它全部添加到
//workspaceItems这个列表中
appWidgets.addAll(sBgAppWidgets);
folders.putAll(sBgFolders);
itemsIdMap.putAll(sBgItemsIdMap);
orderedScreenIds.addAll(sBgWorkspaceScreens);
}
ArrayList currentWorkspaceItems = new ArrayList();//保存的是当前页的workspace的应用信息
ArrayList otherWorkspaceItems = new ArrayList(); //保存的是其他页的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 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 added = mBgAllAppsList.added; //获取所有的已经添加的应用的信息到added列表中
mBgAllAppsList.added = new ArrayList();
// 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 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的数据加载部分。