Launcher
在我个人看来是简单且又复杂的一个模块。 简单是只要认真看,基本能看通UI
部分大体逻辑,稍微动手改一下,就能看到效果,成就感大大滴有。 复杂是和SystemUI
之间强绑定,看起来让我这菜狗CPU
嗡嗡的。

Launcher
继承StatefulActivity
实现Callbacks
涉及类如下
LauncherModel
LauncherAppState
LoaderTask
LoaderResults
进入Launcher
的onCreate
看一下
java
//packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
protected void onCreate(Bundle savedInstanceState) {
LauncherAppState app = LauncherAppState.getInstance(this);
mModel = app.getModel();
if (!mModel.addCallbacksAndLoad(this)) {
if (!internalStateHandled) {
// If we are not binding synchronously, pause drawing until initial bind complete,
// so that the system could continue to show the device loading prompt
mOnInitialBindListener = Boolean.FALSE::booleanValue;
}
}
}
LauncherAppState
采用单例模式 ,在双构造里面引入了老演员InvariantDeviceProfile。 到现在大家不用理解太多。反正知道LauncherAppState里面是嘛都有啊~。
java
public LauncherAppState(Context context) {
this(context, LauncherFiles.APP_ICONS_DB);
}
public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
mContext = context;
//出来吧 神龙 详情看第一篇
mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
mIconProvider = new LauncherIconProvider(context);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
iconCacheFileName, mIconProvider);
//出来吧我的model
mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
iconCacheFileName != null);
mOnTerminateCallback.add(mIconCache::close);
}
LauncherModel
java
LauncherModel(@NonNull final Context context, @NonNull final LauncherAppState app,
@NonNull final IconCache iconCache, @NonNull final AppFilter appFilter,
final boolean isPrimaryInstance) {
mApp = app;
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel,
isPrimaryInstance);
}
LoaderTask
其中的mModelDelegate
是使用的 LauncherModel
传递过来的单例对象。
java
public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,
ModelDelegate modelDelegate, LoaderResults results) {
mApp = app;
mBgAllAppsList = bgAllAppsList;
mBgDataModel = dataModel;
mModelDelegate = modelDelegate;
mResults = results;
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
mUserCache = UserCache.INSTANCE.get(mApp.getContext());
mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
mIconCache = mApp.getIconCache();
}
我们直接进入mModel.addCallbacksAndLoad
这段代码。
java
public boolean addCallbacksAndLoad(@NonNull final Callbacks callbacks) {
synchronized (mLock) {
addCallbacks(callbacks);
return startLoader(new Callbacks[] { callbacks });
}
}
private boolean startLoader(@NonNull final Callbacks[] newCallbacks) {
//省略部分代码
//调用新的执行之前会将老的停掉
stopLoader();
mLoaderTask = new LoaderTask(
mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);
MODEL_EXECUTOR.post(mLoaderTask);
//省略部分代码
}
为了避免重复执行代码,先 LoaderTask
继承了Runnable,
所以直接看run
方法。 允许我可耻的删除部分代码,我们只需要知道在该run 方法里面执行了5步
loadWorkspace
加载workSpace
数据,更新。loadAllApps
加载所有app
,更新。loadDeepShortcuts
快捷方式,就是长按出来的那个小列表,更新。allWidgetsList
加载小组件,更新。loadFolderNames
加载文件夹,更新。
java
public void run() {
synchronized (this) {
//做了判断 如果stop没停止就不能开始
if (mStopped) {
return;
}
}
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
try {
loadWorkspace(allShortcuts, memoryLogger);
} finally {
Trace.endSection();
}
//绑定
mResults.bindWorkspace(true /* incrementBindId */);
logASplit(logger, "bindWorkspace");
//完成workSpace
mModelDelegate.workspaceLoadComplete();
// second step
List<LauncherActivityInfo> allActivityList;
try {
allActivityList = loadAllApps();
} finally {
Trace.endSection();
}
//
mResults.bindAllApps();
logASplit(logger, "bindAllApps");
//更新icon
updateHandler.updateIcons(allActivityList,
LauncherActivityCachingLogic.newInstance(mApp.getContext()),
mApp.getModel()::onPackageIconsUpdated);
// third step
List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
verifyNotStopped();
mResults.bindDeepShortcuts();
updateHandler.updateIcons(allDeepShortcuts,
new ShortcutCachingLogic(), (pkgs, user) -> { });
// Take a break
// fourth step
List<ComponentWithLabelAndIcon> allWidgetsList =
mBgDataModel.widgetsModel.update(mApp, null);
mResults.bindWidgets();
updateHandler.updateIcons(allWidgetsList,
new ComponentWithIconCachingLogic(mApp.getContext(), true),
mApp.getModel()::onWidgetLabelsUpdated);
// fifth step
loadFolderNames();
verifyNotStopped();
updateHandler.finish();
logASplit(logger, "finish icon update");
mModelDelegate.modelLoadComplete();
transaction.commit();
}
注意在每个加载完成的时候都会调用一下对应的mResults.doxxxx()
; 我很好奇bindAllApps
干了啥
java
public void bindAllApps() {
// shallow copy
AppInfo[] apps = mBgAllAppsList.copyData();
int flags = mBgAllAppsList.getFlags();
executeCallbacksTask(c -> c.bindAllApplications(apps, flags), mUiExecutor);
}
protected void executeCallbacksTask(CallbackTask task, Executor executor) {
executor.execute(() -> {
if (mMyBindingId != mBgDataModel.lastBindId) {
Log.d(TAG, "Too many consecutive reloads, skipping obsolete data-bind");
return;
}
for (Callbacks cb : mCallbacksList) {
task.execute(cb);
}
});
}
okok
,我们从上面代码知道Launcher
的oncreart()
方法里面把this
传给了LaucherMode
,然后传给了LoaderResult
,给到了作为参数构建了LoaderTask
。 所以这里其实会回调回Launcher
的bindAllApplications
java
@TargetApi(Build.VERSION_CODES.S)
public void bindAllApplications(AppInfo[] apps, int flags) {
mAppsView.getAppsStore().setApps(apps, flags);
PopupContainerWithArrow.dismissInvalidPopup(this);
if (Utilities.ATLEAST_S) {
Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
DISPLAY_ALL_APPS_TRACE_COOKIE);
}
}
同样bindWorkspace
回调 bindStringCache
方法,大家感兴趣可以看下其他方法。