8-Launcher学习
概述
launcher其实就是一个app,从功能上说,是对手机上其他app的一个管理和启动,从代码上说比其他app多了一个属性,就是在AndroidManifest.xml文件中多了一个“android:name=”android.intent.category.HOME”属性,这个属性就是在启动系统或者按Home键时会过滤这个属性,如果系统中只要一个应用具有这个属性,就会直接跳转到这个界面,也就是这个launcher,如果有多个,会弹出选择框让用户选择并且提示用户是否选择默认设置。
Launcher启动流程
- Launcher是一个应用程序,这个应用程序用来显示系统中已经安装的应用程序
- SyetemServer进程在启动的过程中会启动PackageManagerService将所有应用程序安装完毕
- ActivityManager 向PackageManagerService查询CATEGOR_HOME的Activity启动作为桌面Activity,将Launcher启动起来
- Launcher最终通过recycleview显示所有应用图标,
启动Launcher后,通过LauncherModel控制加载逻辑,LoaderTask开启线程加载数据,LoaderResults进行数据绑定的处理,最后将数据返回给Launcher处理
结构
下面介绍一下桌面的基本结构。首先看下图:
最外层,也就是手机显示层是一个叫做Workspace的控件,其实在Workspace外层还有一个DragLayer层,在他的里面的最上面,是一个叫做SearchDropTargetView的控件,该控件就是搜索或者删除应用的控件。中间最大的一块是CellLayout,一个Workspace包含一个或者多个CellLayout,多个CellLayout横向并排排列,每个CellLayout在宽度上占用一屏,如下图所示:
当用户左右滑动时会切换中间的CellLayout部分,如下图所示:
CellLayout主要的作用是装在快捷方式或者小部件等。用户通过点击这些快捷方式打开应用。中间的指示点叫做PageIndicator,用来指示你当前处于第几个屏幕上面,也就是第几个CellLayout。最下面的四个图标所占的位置叫做Hotseat,主要是放置短信,拨号等最常用的应用图标。用户左右滑动屏幕时,该控件不做滑动处理。
当用户长按桌面时,中间的CellLayout会缩小,下面的Hotseat和上面的SearchDropTargetView会隐藏,从而显示出隐藏的三个菜单按钮。
hotseat
受欢迎的位置
原生Launcher3经典的四种UI模式:
Launcher3的实质其实就是一个Activity包含N个自定义层级的View,不同模式隐藏显示不同的View而已。
关键类
Launcher:主界面Activity,最核心且唯一的Activity。
LauncherAppState:单例对象,构造方法中初始化对象、注册应用安装、卸载、更新,配置变化等广播。这些广播用来实时更新桌面图标等,其receiver的实现在LauncherModel类中,LauncherModel也在这里初始化。
LauncherModel:数据处理类,保存桌面状态,提供读写数据库的API,内部类LoaderTask用来初始化桌面。
InvariantDeviceProfile:一些不变的设备相关参数管理类,其内部包涵了横竖屏模式的DeviceProfile。
WidgetPreviewLoader:存储Widget信息的数据库,内部创建了数据库widgetpreviews.db。
LauncherAppsCompat:获取已安装App列表信息的兼容抽象基类,子类依据不同版本API进行兼容性处理。
AppWidgetManagerCompat:获取AppWidget列表的兼容抽象基类,子类依据不同版本API进行兼容性处理。
LauncherStateTransitionAnimation:各类动画总管处理执行类,负责各种情况下的各种动画效果处理。
IconCache:图标缓存类,应用程序icon和title的缓存,内部类创建了数据库app_icons.db。
LauncherProvider:核心数据库类,负责launcher.db的创建与维护。
LauncherAppWidgetHost:AppWidgetHost子类,是桌面插件宿主,为了方便托拽等才继承处理的。
LauncherAppWidgetHostView:AppWidgetHostView子类,配合LauncherAppWidgetHost得到HostView。
LauncherRootView:竖屏模式下根布局,继承了InsettableFrameLayout,控制是否显示在状态栏等下面。
DragLayer:一个用来负责分发事件的ViewGroup。
DragController:DragLayer只是一个ViewGroup,具体的拖拽的处理都放到了DragController中。
BubblTextView:图标都基于他,继承自TextView。
DragView:拖动图标时跟随手指移动的View。
Folder:打开文件夹展示的View。
FolderIcon:文件夹图标。
DragSource/DropTarget:拖拽接口,DragSource表示图标从哪开始拖,DropTarget表示图标被拖到哪去。
ItemInfo:桌面上每个Item的信息[[1-数据结构]],包括在第几屏、第几行、第几列、宽高等信息;该对象与数据库中记录一一对应;该类有多个子类,譬如FolderIcon的FolderInfo、BubbleTextView的ShortcutInfo等。
启动主流程
需要特别注意上图中红色的两步。在setContentView之后我们其实又进行了一次依据设备属性的layout操作,接着才进行异步数据加载的,所以我们的重点会放在LauncherModel的loader方法中。
在启动Launcher时数据加载绑定其实分了两大类,workspace与allApps(widgets)的加载,他们都是通过异步加载回调UI绑定数据的,下面我们先看下workspace的加载绑定流程,如下:
可以发现,到此其实UI和数据都已经显示OK了,我们接着关注一下AllApps和Widget的加载流程,如下:
新应用安装后自动显示到桌面
在LauncherAppState的构造方法中,LauncherModel被注册到了LauncherApps中,LauncherApps是一个系统服务,可以用来查询和监听系统内应用的安装卸载等变化。 LauncherModel类继承了LauncherApps.Callback并实现了其回调方法。 所以当有新应用安装成功后,会回调此方法。
将launch3代码导出
不同api是怎么适配的?
startDockOrHome
startHomeOnDisplay
ActivityTaskManagerService startHomeOnDisplay
1 |
|
RootActivityContainer
1 |
|
我们看上面的3437行,获取Intent,再看3451行,如果不为空,则启动HomeActivity,我们看一下这个Intent是什么的Intent:
上面的3424行,有个Intent.CATEGORY_HOME,我们在Intent中找到这个属性的代码:
1 |
|
ContentProvider
在Application和ContentProvider同时存在时,ContentProvider 的onCreate方法要比Application的onCreate方法先启动
BIND_APPLICATION—–>handleBindApplication
先 installContentProviders 后 callApplicationOnCreate