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显示所有应用图标,
    image.png

启动Launcher后,通过LauncherModel控制加载逻辑,LoaderTask开启线程加载数据,LoaderResults进行数据绑定的处理,最后将数据返回给Launcher处理

结构

下面介绍一下桌面的基本结构。首先看下图:

image.png

最外层,也就是手机显示层是一个叫做Workspace的控件,其实在Workspace外层还有一个DragLayer层,在他的里面的最上面,是一个叫做SearchDropTargetView的控件,该控件就是搜索或者删除应用的控件。中间最大的一块是CellLayout,一个Workspace包含一个或者多个CellLayout,多个CellLayout横向并排排列,每个CellLayout在宽度上占用一屏,如下图所示:

image.png

当用户左右滑动时会切换中间的CellLayout部分,如下图所示:
image.png

CellLayout主要的作用是装在快捷方式或者小部件等。用户通过点击这些快捷方式打开应用。中间的指示点叫做PageIndicator,用来指示你当前处于第几个屏幕上面,也就是第几个CellLayout。最下面的四个图标所占的位置叫做Hotseat,主要是放置短信,拨号等最常用的应用图标。用户左右滑动屏幕时,该控件不做滑动处理。

当用户长按桌面时,中间的CellLayout会缩小,下面的Hotseat和上面的SearchDropTargetView会隐藏,从而显示出隐藏的三个菜单按钮。

image.png

hotseat
受欢迎的位置

原生Launcher3经典的四种UI模式:
image.png
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等。

启动主流程

image.png

需要特别注意上图中红色的两步。在setContentView之后我们其实又进行了一次依据设备属性的layout操作,接着才进行异步数据加载的,所以我们的重点会放在LauncherModel的loader方法中。

在启动Launcher时数据加载绑定其实分了两大类,workspace与allApps(widgets)的加载,他们都是通过异步加载回调UI绑定数据的,下面我们先看下workspace的加载绑定流程,如下:
image.png
可以发现,到此其实UI和数据都已经显示OK了,我们接着关注一下AllApps和Widget的加载流程,如下:
image.png

image.png

新应用安装后自动显示到桌面

在LauncherAppState的构造方法中,LauncherModel被注册到了LauncherApps中,LauncherApps是一个系统服务,可以用来查询和监听系统内应用的安装卸载等变化。 LauncherModel类继承了LauncherApps.Callback并实现了其回调方法。 所以当有新应用安装成功后,会回调此方法。

将launch3代码导出

不同api是怎么适配的?

startDockOrHome
startHomeOnDisplay
ActivityTaskManagerService startHomeOnDisplay

1
2
3
4
5
6
7
8
@Override  
public boolean startHomeOnDisplay(int userId, String reason, int displayId,
boolean allowInstrumenting, boolean fromHomeKey) {
synchronized (mGlobalLock) {
return mRootActivityContainer.startHomeOnDisplay(userId, reason, displayId,
allowInstrumenting, fromHomeKey);
}
}

RootActivityContainer

1
2
3
4
5
6
7
8
9
boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,  
boolean fromHomeKey) {
....
homeIntent = mService.getHomeIntent();
...
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
displayId);
return true;
}

我们看上面的3437行,获取Intent,再看3451行,如果不为空,则启动HomeActivity,我们看一下这个Intent是什么的Intent:

image.png
上面的3424行,有个Intent.CATEGORY_HOME,我们在Intent中找到这个属性的代码:

1
public static final String CATEGORY_HOME = "android.intent.category.HOME";

ContentProvider

在Application和ContentProvider同时存在时,ContentProvider 的onCreate方法要比Application的onCreate方法先启动
BIND_APPLICATION—–>handleBindApplication
先 installContentProviders 后 callApplicationOnCreate


8-Launcher学习
http://peiniwan.github.io/2024/04/3dceb00eb5b3.html
作者
六月的雨
发布于
2024年4月6日
许可协议