Launcher3 是 AOSP 中的默认主屏幕应用,负责设备解锁后用户第一眼所见的交互体验。它管理工作区上的应用图标、全部应用抽屉、桌面小组件、文件夹、拖拽逻辑、大屏设备任务栏;并且通过 Quickstep 组件集成,负责最近应用概览界面。代码位于packages/apps/Launcher3/,由大约十五个顶层目录的 Java、Kotlin 源码组成,外加实现手势导航与最近任务功能的quickstep/模块。本章完整讲解 Launcher3 整体架构:从后台线程加载工作区数据的模型层,到渲染图标和小组件的视图层级,再到串联全部逻辑的拖拽引擎。每一节均引用真实 AOSP 源码文件,并摘录关键代码片段。49.1 Launcher3 架构49.1.1 项目目录结构Launcher3 顶层目录组织结构如下:packages/apps/Launcher3/ src/ # Launcher核心源码 quickstep/ # 手势导航、最近任务、任务栏 src_no_quickstep/ # 不启用quickstep编译版本的桩代码 src_plugins/ # 插件接口 shared/ # 多变体共用代码(例如TestProtocol) res/ # 资源文件(布局、XML配置) protos/ # Protocol Buffer定义 protos_overrides/ # 各编译版本proto覆盖配置 modules/ # Compose模块(例如modules/widgetpicker) aconfig/ # aconfig功能开关定义 dagger/ # Dagger依赖注入模块 go/ # Android Go版本覆盖配置 checks/ # Lint与error‑prone代码检查 tests/ # 单元测试与集成测试 tools/ # 编译工具 AndroidManifest.xml # 应用清单文件 Android.bp # Soong编译脚本项目不再有独立的compose/目录;基于 Compose 编写的代码现在存放于modules/目录下,典型如modules/widgetpicker/。主要源码树src/com/android/launcher3/包含以下关键子目录:子目录用途allapps/全部应用抽屉、字母排序列表、标签页dragndrop/拖拽控制器、拖拽层、拖拽视图folder/文件夹图标、文件夹分页视图、网格排布器widget/小组件宿主视图、小组件选择器model/数据模型、加载任务、数据库icons/图标缓存、图标提供器graphics/主题管理器、遮罩、形状代理statemanager/Launcher 状态机celllayout/单元格布局参数、重排算法search/搜索算法接口responsive/响应式网格配置touch/触摸控制器、点击事件处理anim/动画工具类config/功能开关配置deviceprofile/设备专属布局配置views/通用视图工具popup/长按弹出菜单shortcuts/应用快捷方式(Deep Shortcuts)logging/统计与事件日志49.1.2 主 Activity:Launcher入口类为Launcher.java,约 2900 行代码,继承StatefulActivityLauncherState:// src/com/android/launcher3/Launcher.java public class Launcher extends StatefulActivityLauncherState implements Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListenerLauncherOverlayPlugin {StatefulActivity是泛型基类,与StateManager配合,处理 Launcher 各个状态之间的切换(NORMAL、ALL_APPS、SPRING_LOADED、EDIT_MODE 等)。Callbacks接口定义在BgDataModel中,规定模型层向 UI 交付已加载数据的契约。Launcher 的核心成员变量构成视图层级:// src/com/android/launcher3/Launcher.java Workspace? mWorkspace; DragLayer mDragLayer; Hotseat mHotseat; ActivityAllAppsContainerViewLauncher mAppsView; AllAppsTransitionController mAllAppsController; ScrimView mScrimView; LauncherDragController mDragController;49.1.3 Launcher 生命周期:onCreateonCreate是初始化主流程,执行顺序如下:// src/com/android/launcher3/Launcher.java, onCreate() protected void onCreate(Bundle savedInstanceState) { // 1. 启动追踪埋点 TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT); super.onCreate(savedInstanceState); mWallpaperThemeManager = new WallpaperThemeManager(this); // 2. 获取应用全局状态 LauncherAppState app = LauncherAppState.getInstance(this); mModel = app.getModel(); // 3. 初始化设备配置与旋转 mRotationHelper = new RotationHelper(this); InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); initDeviceProfile(idp); // 4. 初始化拖拽控制器与状态管理器 initDragController(); mAllAppsController = new AllAppsTransitionController(this); mStateManager = new StateManager(this, NORMAL); // 5. 小组件基础设施 mAppWidgetManager = new WidgetManagerHelper(this); mAppWidgetHolder = LauncherWidgetHolder.newInstance(this); // 6. 加载布局视图 setupViews(); // 7. 开启小组件监听 mAppWidgetHolder.startListening(); // 8. 启动模型数据加载 mModel.addCallbacksAndLoad(this); }49.1.4 LauncherAppState:单例中枢LauncherAppState现已改为 Kotlin 数据类,聚合多个核心单例:// src/com/android/launcher3/LauncherAppState.kt @Deprecated("Inject the specific targets directly instead of using LauncherAppState") data class LauncherAppState @Inject constructor( @ApplicationContext val context: Context, val iconProvider: LauncherIconProvider, val iconCache: IconCache, val model: LauncherModel, val invariantDeviceProfile: InvariantDeviceProfile, @Named("SAFE_MODE") val isSafeModeEnabled: Boolean, )注意该类标记@Deprecated:代码正在迁移,不再通过该单例,改为直接 Dagger 注入各个组件。伴生对象依旧保留传统INSTANCE与getInstance()做兼容性。49.1.5 LauncherModel:数据主干LauncherModel注解@LauncherAppSingleton,管理 Launcher 全部内存数据,由 Dagger 注入构造:// src/com/android/launcher3/LauncherModel.kt @LauncherAppSingleton class LauncherModel @Inject constructor( @ApplicationContext private val context: Context, private val taskControllerProvider: ProviderModelTaskController, private val iconCache: IconCache, private val prefs: LauncherPrefs, private val installQueue: ItemInstallQueue, @Named("ICONS_DB") dbFileName: String?, initializer: ModelInitializer, lifecycle: DaggerSingletonTracker, val modelDelegate: ModelDelegate, private val mBgAllAppsList: AllAppsList, private val mBgDataModel: BgDataModel, private val loaderFactory: LoaderTaskFactory, private val binderFactory: BaseLauncherBinderFactory, val modelDbController: ModelDbController, dumpManager: DumpManager, ) : LauncherDumpable {模型维护两个关键数据结构:BgDataModel:保存工作区条目、文件夹、桌面小组件、屏幕顺序AllAppsList:保存全部可启动 Activity 列表数据加载运行在MODEL_EXECUTOR专属后台线程。模型通过mModelLoaded、mLoaderTask、lastLoadId追踪加载状态。// src/com/android/launcher3/LauncherModel.kt fun isModelLoaded() = synchronized(mLock) { mModelLoaded mLoaderTask == null !mModelDestroyed }49.1.6 模型‑视图分离架构严格执行模型视图分离:由 Launcher 实现的Callbacks接口定义绑定契约:bindItems()— 交付工作区条目(图标、快捷方式)bindAppWidgets()— 交付小组件实例bindAllApplications()— 交付完整应用列表bindWidgetsModel()— 交付小组件目录,供给选择器使用数据写入通过LauncherModel.getWriter()获取ModelWriter。所有数据库变更均在模型线程执行,保证数据一致性。49.1.7 状态机StateManager是通用状态机,驱动 Launcher 各个状态之间带动画的切换;每个状态是LauncherState的子类。// src/com/android/launcher3/LauncherState.java public abstract class LauncherState implements BaseStateLauncherState { public static final int HOTSEAT_ICONS = 1 0; public static final int ALL_APPS_CONTENT = 1 1; public static final int WORKSPACE_PAGE_INDICATOR = 1 5; public static final int FLOATING_SEARCH_BAR = 1 7; // ... public static final int FLAG_MULTI_PAGE = BaseState.getFlag(0); public static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = BaseState.getFlag(2); public static final int FLAG_RECENTS_VIEW_VISIBLE = BaseState.getFlag(6);每个状态拥有 ordinal 字段,取值来自TestProtocol中对应的*_STATE_ORDINAL常量,传给构造函数。这些值不是连续 UI 层级序号,而是与测试框架共用的稳定标识符。状态Ordinal说明NORMAL0默认工作区视图SPRING_LOADED1拖拽过程中工作区收缩状态OVERVIEW2Quickstep 最近任务视图OVERVIEW_MODAL_TASK3任务菜单打开QUICK_SWITCH4快速切换手势ALL_APPS5全部应用抽屉打开BACKGROUND_APP6应用处于前台HINT_STATE7上滑手势提示指示器HINT_STATE_TWO_BUTTON8三键导航提示指示器OVERVIEW_SPLIT_SELECT9分屏选择模式EDIT_MODE10工作区自定义编辑模式DESKTOP_DRAG_MODE11拖拽进入桌面窗口模式StateManager驱动带动画的状态切换:// src/com/android/launcher3/statemanager/StateManager.java public class StateManagerS extends BaseStateS, T extends StatefulContainerS { private final AnimationStateS mConfig = new AnimationState(); private final T mContainer; private final ArrayListStateListenerS mListeners = new ArrayList(); private S mState; private S mLastStableState; private S mCurrentStableState; }StateHandlerS[]负责应用每个状态专属的属性变更。例如AllAppsTransitionController在状态切换过程中调整全部应用面板的垂直位置与透明度。49.1.8 Dagger 依赖注入Launcher3 使用 Dagger 做依赖注入,关键注解:@LauncherAppSingleton— 作用域为应用整个生命周期@ApplicationContext— 应用级 Context@Inject— 构造函数注入@Named— 用于区分同一类型不同实例(例如 "ICONS_DB")DI 图根节点是LauncherAppComponent,提供InvariantDeviceProfile、LauncherModel、IconCache、ThemeManager49.2 应用图标与网格49.2.1 ItemInfo 类继承体系主屏幕上每一个元素:应用图标、快捷方式、小组件、文件夹,全部是ItemInfo的子类。// src/com/android/launcher3/model/data/ItemInfo.java public class ItemInfo { public int id = NO_ID; public int itemType; public int container = NO_ID; public int screenId = -1; public int cellX = -1; public int cellY = -1; public int spanX = 1; public int spanY = 1; public int minSpanX = 1; public int minSpanY = 1; public int rank = 0; public CharSequence title;itemType字段决定实际子类类型:常量值含义ITEM_TYPE_APPLICATION0应用快捷方式ITEM_TYPE_FOLDER2文件夹容器ITEM_TYPE_APPWIDGET4桌面小组件ITEM_TYPE_DEEP_SHORTCUT6固定深度快捷方式ITEM_TYPE_TASK7最近任务条目ITEM_TYPE_QSB8搜索栏占位ITEM_TYPE_APP_GROUP10分屏应用配对ITEM_TYPE_FILE_SYSTEM_FILE12主屏幕文件container字段标记条目所属容器:// src/com/android/launcher3/LauncherSettings.java public static final int CONTAINER_DESKTOP = -100; public static final int CONTAINER_HOTSEAT = -101; public static final int CONTAINER_ALL_APPS = -104;49.2.2 CellLayout:网格容器CellLayout是基础网格容器。每一页工作区、Hotseat 底部栏都是CellLayout实例,管理网格单元与条目摆放。// src/com/android/launcher3/CellLayout.java public class CellLayout extends ViewGroup { @Thunk int mCellWidth; @Thunk int mCellHeight; protected Point mBorderSpace; protected int mCountX; protected int mCountY;每个CellLayout持有GridOccupancy记录哪些单元格被占用:// src/com/android/launcher3/util/GridOccupancy.java public class GridOccupancy { boolean[][] cells; int countX; int countY; }条目位置由CellLayoutLayoutParams定义:// src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java public class CellLayoutLayoutParams extends MarginLayoutParams { public int cellX; public int cellY; public int cellHSpan; public int cellVSpan; public int tmpCellX; public int tmpCellY; }CellLayout内部子容器ShortcutAndWidgetContainer负责子 View 实际布局。这种分离让CellLayout专注网格逻辑,子容器处理 ViewGroup 布局流程。49.2.3 Workspace:分页容器Workspace继承PagedView,包含多个CellLayout页面。// src/com/android/launcher3/Workspace.java public class WorkspaceT extends View PageIndicator extends PagedViewT implements DropTarget, DragSource, View.OnTouchListener, LauncherOverlayCallbacks, Insettable {Workspace 能力:主屏幕页面水平左右滑动分页页面之间条目拖拽根据内容自动创建、删除页面通过WallpaperOffsetInterpolator实现壁纸滚动拖拽时的弹簧加载模式,页面整体收缩49.2.4 BubbleTextView:图标视图BubbleTextView是自定义 TextView 子类,渲染应用图标。// src/com/android/launcher3/BubbleTextView.java public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, DraggableView, Poppable {它同时渲染上方图标(Compound drawable)和下方标签文字。主要特性:通知角标圆点:有通知时由DotRenderer绘制下载进度环:应用安装过程的进度遮罩主题图标:Material You 主题生效时渲染单色图标运行状态指示器:任务栏图标标记正在运行的应用