AndroidM: Launcher3: 流程源码分析

时间:2021-10-21 09:20:03

  前一阵子太忙了,但有不知道忙的什么,每天都在处理客户的需求,很少有时间总结知识。自从接收Launcher之后还没有做总结,以后后陆续的总结Launcher开发过程中遇到的问题。

  Launcher的实质也就是一个普通应用,它只是比普通应用多配置了Category 的android:name=”android.intent.category.HOME”属性而已。当Android开机启动成功以后框架层会尝试启动包含上面属性配置的Activity,这样被启动的那个Activity就成了桌面。当我们按下设备的Home键时也会触发包含该属性的Activity。只不过当系统中只存在一个包含该属性的应用时,无论开机还是Home键触发都只会自动启动默认的;当存在多个时无论哪种触发都会弹出选择框进行选择设置。如果你想写死的话可以在ActivityManagerService服务中将该入口堵死。

AndroidM: Launcher3: 流程源码分析


  一:launcher进程启动过程

  首先看一下启动的流程图:

AndroidM: Launcher3: 流程源码分析

Activity Manager通过发送Intend来启动Launcher。

Intent intent = new Intent(mTopAction, mTopData != null ? 
  Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) 
{
    intent.addCategory(Intent.CATEGORY_HOME);
}
startActivityLocked(null, intent, null, null, 0, aInfo,
  null, null, 0, 0, 0, false, false);
如果你要开机启动一个替换Launcher的程序,只要在程序<intent-filter>里面加入action.MAIN 、category.HOME、category.DEFAULT就可以。如果出现多个程序都加入这种intent,系统会弹出让你选择哪个作为启动器。

 二:Launcher初始化——LauncherApplication。

Application是一个全局的应用类,在AndroidManifest.xml可以找到Application标签。

Android四大组件的声明都需要放到application标签里面,默认使用的是系统的Application类,如果你重载了它。就需要在标签,name属性下写上你的新的Application类名。Launcher里面就是继承了Application为LauncherApplication。应用启动的时候首先会加载Application。我们可以看到Launcher主类Launcher.java的onCreate函数里面,第一个就是获取Application的实例。LauncherApplication app = ((LauncherApplication)getApplication());

LauncherApplication大部分工作就是在初始化工作和注册一些监听器。主要都是用来监听应用的安装更新删除等导致Launcher数据库变化的操作。Launcher数据都是使用contentprovider来提供数据。

其中注册的监听接口是

 private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) 
    {
        @Override
        public void onChange(boolean selfChange) 
        {
       //重新加载界面数据
            mModel.startLoader(LauncherApplication.this, false);
        }
    };

LauncherSettings.Favorites.CONTENT_URI里面数据发生变化的时候,都会调用mModel.startLoader()接口,重新加载Launcher的数据。startLoader这一块涉及Launcher所有数据加载。剩下的都是返回初始化时候创建的对象或者获取屏幕密度、获取是否大屏幕。后面很多处理都需要判断是否是大屏幕。

 三:最核心且唯一的Activity-- Launcher.java

下面先给出主要的一些类文件的大致含义,这样才能方便理解代码,如下:

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的信息数据结构,包括在第几屏、第几行、第几列、宽高等信息;该对象与数据库中记录一一对应;该类有多个子类,譬如FolderIcon的FolderInfo、BubbleTextView的ShortcutInfo等。

Launcher启动主流程图:

AndroidM: Launcher3: 流程源码分析

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

在启动Launcher时数据加载绑定其实分了两大类,workspace与allApps(widgets)的加载,他们都是通过异步加载回调UI绑定数据的,下面我们先看下workspace的加载绑定流程,如下:

AndroidM: Launcher3: 流程源码分析

到此其实UI和数据都已经显示OK了,我们接着关注一下AllApps和Widget的加载流程,如下:

AndroidM: Launcher3: 流程源码分析

这里最主要的工作是加载界面数据:mModel.startLoader(this, true); 这块实现是在LauncherModel里面实现的

 这些总结了网上的资源和自己的认识,后续开发过程中会逐步对Launcher进行详细的代码分析。