Android 10.0 launcher 启动流程
一、Launcher 简介
Launcher 是 Android 系统不可缺少的部分,我们通常称之为 Android 系统的桌面,它在 Android 系统中起着重要的作用。
- Launcher 是 Android 系统的启动器。在 Launcher 中可以启动你想要使用的应用程序。
- Launcher 也是应用程序的管理器。可用来对应用程序进行基础的管理,比如删除或者展示应用程序。
- Launcher 更重要的意义在于它是一个桌面。在 Android 的桌面上,你可以放置各种快捷方式、桌面小部件,也可以通过 Launcher 更换壁纸,使你的桌面更炫更便利更加个性化。
二、Launcher 结构
在 Launcher 中主要有两大组件:
- UI组件:桌面(Workspace)、应用程序菜单(Allapps)、快捷启动栏(Hotseat)、搜索和页面指示条、快捷菜单。
- 桌面组件:应用程序的快捷方式及相关视图实现(DeepShortcuts)、文件夹及相关视图实现、桌面小部件及相关组件(Widgets)。
UI组件.png
桌面组件.png
三、launcher 启动
参考Android系统开机到Launcher启动流程分析、Android 10.0 launcher启动流程。
四、主要文件和类
- Launcher.java:launcher中主要的activity。
- LoaderTask.java: 可运行用于加载启动器内容的线程: 工作区图标 、小部件 、所有应用程序图标 、应用程序快捷方式。
- LauncherAppState.java:用于存储全局变量,比如:缓存(各种cache),维护内存数据的类(LauncherModel)。
- DragLayer.java:launcher layout的rootview。DragLayer实际上也是一个抽象的界面,用来处理拖动和对事件进行初步处理然后按情况分发下去,角色是一个controller。它首先用onInterceptTouchEvent(MotionEvent)来拦截所有的touch事件,如果是长按item拖动的话不把事件传下去,直接交由onTouchEvent()处理,这样就可以实现item的移动了,如果不是拖动item的话就把事件传到目标view,交有目标view的事件处理函数做相应处理。如过有要对事件的特殊需求的话可以修改onInterceptTouchEvent(MotionEvent)来实现所需要的功能。
- DragController.java:为Drag定义的一个接口。包含一个接口,两个方法和两个静态常量。接口为DragListener(包含onDragStart(),onDragEnd()两个函数),onDragStart()是在刚开始拖动的时候被调用,onDragEnd()是在拖动完成时被调用。在launcher中典型的应用是DeleteZone,在长按拖动item时调用onDragStart()显示,在拖动结束的时候onDragEnd()隐藏。两个函数包括startDrag()和setDragItemInfo().startDrag()用于在拖动是传递要拖动的item的信息以及拖动的方式,setDragItemInfo()用于传递item的参数信息(包括位置以及大小)。两个常量为DRAG_ACTION_MOVE,DRAG_ACTION_COPY来标识拖动的方式,DRAG_ACTION_MOVE为移动,表示在拖动的时候需要删除原来的item,DRAG_ACTION_COPY为复制型的拖动,表示保留被拖动的item。
- LauncherModel.java:辅助的文件。里面有许多封装的对数据库的操作。包含几个线程,其中最主要的是ApplicationsLoader和DesktopItemsLoader。ApplicationsLoader在加载所有应用程序时使用,DesktopItemsLoader在加载workspace的时候使用。其他的函数就是对数据库的封装,比如在删除,替换,添加程序的时候做更新数据库和UI的工作。
- Workspace.java:抽象的桌面。由N个celllaout组成,从cellLayout更高一级的层面上对事件的处理。
- LauncherProvider.java:launcher的数据库,里面存储了桌面的item的信息。在创建数据库的时候会loadFavorites(db)方法,loadFavorites()会解析xml目录下的default_workspace.xml文件,把其中的内容读出来写到数据库中,这样就做到了桌面的预制。
- CellLayout.java:组成workspace的view,继承自viewgroup,既是一个dragSource,又是一个dropTarget,可以将它里面的item拖出去,也可以容纳拖动过来的item。在workspace_screen里面定了一些它的view参数。
- ItemInfo.java:对item的抽象,所有类型item的父类,item包含的属性有id(标识item的id),cellX(在横向位置上的位置,从0开始),cellY(在纵向位置上的位置,从0开始) ,spanX(在横向位置上所占的单位格),spanY(在纵向位置上所占的单位格),screen(在workspace的第几屏,从0开始),itemType(item的类型,有widget,search,application等),container(item所在的)。
- LauncherSettings.java:字符串的定义。数据库项的字符串定义,另外在这里定义了container的类型,还有itemType的定义,除此还有一些特殊的widget(如search,clock的定义等)的类型定义。
五、launcher 源码分析
launcher.java
是 launcher 主要、第一个启动的 activity,在其里面进行显示、初始化一些 View。
launcher#onCreate()
// launcher.java protected void onCreate(Bundle savedInstanceState) { // 省略部分代码...... Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT, TraceHelper.FLAG_UI_EVENT); if (DEBUG_STRICT_MODE) { //StrictMode被称为严苛模式,google提供用来进行测试的类 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() // or .detectAll() for all detectable problems .penaltyLog() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() .build()); } // 省略部分代码...... super.onCreate(savedInstanceState); // 单例模式,初始化LauncherAppState LauncherAppState app = LauncherAppState.getInstance(this); mOldConfig = new Configuration(getResources().getConfiguration()); // 获取LauncherModel实例 mModel = app.getModel(); mRotationHelper = new RotationHelper(this); InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); // 初始化手机固件信息对象DeviceProfile initDeviceProfile(idp); idp.addOnChangeListener(this); // 获取sharedPreferences mSharedPrefs = Utilities.getPrefs(this); // 获取IconCache实例,此类主要保存图标信息 mIconCache = app.getIconCache(); mAccessibilityDelegate = createAccessibilityDelegate(); // 拖拽 mDragController = new LauncherDragController(this); mAllAppsController = new AllAppsTransitionController(this); mStateManager = new StateManager<>(this, NORMAL); mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs); // 获取AppWidgetManager实例,用来管理widge mAppWidgetManager = new WidgetManagerHelper(this); mAppWidgetHost = createAppWidgetHost(); mAppWidgetHost.startListening(); // 设置布局 inflateRootView(R.layout.launcher); // 初始化View,进行各种View的初始化事件绑定 setupViews(); crossFadeWithPreviousAppearance(); mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots); boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this); if (internalStateHandled) { if (savedInstanceState != null) { // InternalStateHandler has already set the appropriate state. // We dont need to do anything. savedInstanceState.remove(RUNTIME_STATE); } } restoreState(savedInstanceState); mStateManager.reapplyState(); if (savedInstanceState != null) { int[] pageIds = savedInstanceState.getIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS); if (pageIds != null) { mPagesToBindSynchronously = IntSet.wrap(pageIds); } } // 加载、绑定数据(这里与之前版本的 startLoader() 作用一样) if (!mModel.addCallbacksAndLoad(this)) { if (!internalStateHandled) { Log.d(BAD_STATE, "Launcher onCreate not binding sync, prevent drawing"); // 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; } } // For handling default keys setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); setContentView(getRootView()); if (mOnInitialBindListener != null) { //getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener); } getRootView().dispatchInsets(); // 注册屏幕关闭广播 registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)); if (mLauncherCallbacks != null) { mLauncherCallbacks.onCreate(savedInstanceState); } mOverlayManager = getDefaultOverlay(); PluginManagerWrapper.INSTANCE.get(this).addPluginListener(this, LauncherOverlayPlugin.class, false /* allowedMultiple */); mRotationHelper.initialize(); TraceHelper.INSTANCE.endSection(traceToken); mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener( () -> getStateManager().goToState(NORMAL)); if (Utilities.ATLEAST_R) { getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING); } setTitle(R.string.home_screen); }
从代码中可以看出,首先调用了 LauncherAppState.getInstance(this)
来初始化一个单例对象 ,而LauncherAppState
里面保存了一些比较常用的对象,方便其他地方通过单例来获取,比如 IconCache、LauncherModel
等;并且注册了广播监听器和 ContentObserver
;设置布局 launcher.xml
,调用 setupViews()
又是一些 View
的初始化,设置回调监听等。
总结一下 onCreate()
的工作:初始化对象、加载布局、注册一些事件监听、以及开启数据加载。