LauncherModel继承BroadcastReceiver,显然是一个广播接收者。在上一篇Launcher的启动中讲到桌面数据的加载工作是在LauncherModel中执行的,那么它是如何加载数据的呢?下面将分析Launcher和LauncherModel的通讯方式以及LauncherModel加载桌面数据的过程。
首先分析的是Launcher和LauncherModel的通讯方式:
(1)LauncherModel.Callback回调接口:LauncherModel通过接口输送已经加载完成的数据给Launcher。
//在Launcher.java中持有LauncherModel对象
mModel = app.setLauncher(this);
继续分析setLauncher(Launcher launcher)方法
//返回LauncherModel
LauncherModel setLauncher(Launcher launcher) {
getLauncherProvider().setLauncherProviderChangeListener(launcher);
mModel.initialize(launcher);
mAccessibilityDelegate = ((launcher != null) && Utilities.isLmpOrAbove()) ?
new LauncherAccessibilityDelegate(launcher) : null;
return mModel;
}
以上方法引用了此LauncherModel中的initialize(Callbacks callbacks);方法。且到LauncherModel中分析
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
// Disconnect any of the callbacks and drawables associated with ItemInfos on the
// workspace to prevent leaking Launcher activities on orientation change.
unbindItemInfosAndClearQueuedBindRunnables();
mCallbacks = new WeakReference<Callbacks>(callbacks);
}
}
发现传入的参数是Callbacks对象,而Launcher实现了LauncherModel.Callbacks接口,显然LauncherModel和Launcher就建立了联系。
从而完成了Launcher在LauncherModel中注册接口,将接口实现的引用注册到LauncherModel中,并且返回已经完成初始化的LauncherModel的引用。LauncherModel的所有操作结果都会通过callbacks中定义的各个回调接口中的方法通知给Launcher,并由Launcher分发给不同的桌面组件或者Launcher自身。
LauncherModel提供的Callbacks接口:
public interface Callbacks {
//如果Launcher在加载完成之前被强制暂停,那么需要通过这个回调方法通知Launcher
//在它再次显示的时候重新执行加载过程
public boolean setLoadOnResume();
//获取当前屏幕序号
public int getCurrentWorkspaceScreen();
//启动桌面数据绑定
public void startBinding();
//批量绑定桌面组件:快捷方式列表,列表的开始位置,列表结束的位置,是否使用动画
public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,
boolean forceAnimateIcons);
//批量绑定桌面页,orderedScreenIds 序列化后的桌面页列表
public void bindScreens(ArrayList<Long> orderedScreenIds);
public void bindAddScreens(ArrayList<Long> orderedScreenIds);
//批量绑定文件夹,folders 文件夹映射列表
public void bindFolders(LongArrayMap<FolderInfo> folders);
//绑定任务完成
public void finishBindingItems();
//批量绑定小部件,info 需要绑定到桌面上的小部件信息
public void bindAppWidget(LauncherAppWidgetInfo info);
//绑定应用程序列表界面的应用程序信息,apps 需要绑定到应用程序列表中的应用程序列表
public void bindAllApplications(ArrayList<AppInfo> apps);
// Add folders in all app list.
public void bindAllApplications2Folder(ArrayList<AppInfo> apps, ArrayList<ItemInfo> items);
//批量添加组件
public void bindAppsAdded(ArrayList<Long> newScreens,
ArrayList<ItemInfo> addNotAnimated,
ArrayList<ItemInfo> addAnimated,
ArrayList<AppInfo> addedApps);
//批量更新应用程序相关的快捷方式或者入口
public void bindAppsUpdated(ArrayList<AppInfo> apps);
public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,
ArrayList<ShortcutInfo> removed, UserHandleCompat user);
public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
// 从桌面移除一些组件,当应用程序被移除或者禁用的时候调用
public void bindComponentsRemoved(ArrayList<String> packageNames,
ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);
public void bindAllPackages(WidgetsModel model);
//全局搜索或者搜索属性更新
public void bindSearchablesChanged();
public boolean isAllAppsButtonRank(int rank);
/**
* 指示正在绑定的页面
* @param page 桌面页序号
*/
public void onPageBoundSynchronously(int page);
//输出当前Launcher信息到本地文件中
public void dumpLogsToLocalData();
}
(2)线程处理
@Thunk DeferredHandler mHandler = new DeferredHandler();
@Thunk LoaderTask mLoaderTask;
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
@Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
Launcher和LauncherModel运行在Launcher这个应用程序的主线程中, sWorkerThread只是Launcher应用程序主线程下的一个子线程,对于线程和线程之间的消息交互,一个比较好的方案是将任务抛到目标线程的处理器中,为此,LauncherModel为sWorkerThread在主线程中创建了一个处理器,以实现sWorkerThread和Launcher所在进程之间的信息交互。
(3)广播接口:
LauncherModel继承了BroadcastReceiver,因此可以接收来自Launcher或其他地方的广播,在onReceive(Context context, Intent intent)方法中做出相应的处理。
来个分割线,分析上面加载绑定数据过程的几个方法:
LauncherModel负责桌面数据的加载,即调用startLoader方法启动线程,加载数据。