在Android启动过程-万字长文(Android14)中介绍了Android系统的启动过程,本篇文章将继续介绍桌面应用Launcher。
一、Launcher介绍
- 在Android启动过程-万字长文(Android14)中提到Launcher是Android系统启动后,由SystemServer
Activity Manager Service (AMS)
加载的第一个应用程序
- Launcher又被称为桌面程序,负责Android桌面的启动和管理
- 用户使用的应用程序(App)都是通过Launcher来启动的
二、下载及编译
2.1 下载
| git clone https://android.googlesource.com/platform/packages/apps/Launcher3 |
| git checkout android14-release |
2.2 编译
使用AndroidStudio编译下载好的Launcher3工程
编译过程中遇到问题及解决方案可以参考以下博客:
三、源码解析
3.1 AndroidManifest.xml
在项目根目录的AndroidManifest.xml,定义了Launcher做为桌面程序的属性:
| <application> |
| <activity |
| android:name="com.android.launcher3.Launcher" |
| android:launchMode="singleTask"> |
| <intent-filter> |
| <category android:name="android.intent.category.HOME" /> |
| </intent-filter> |
| </activity> |
| </application> |
- android.intent.category.HOME: 告诉系统这是一个启动器(Launcher)应用程序,系统在初始化完成后会通过
ActivityTaskManagerService
的getHomeIntent
方法获取和启动桌面程序。具体可参见Android启动过程-万字长文(Android14)
- 开发人员也可以自己开发一个桌面程序(如微软桌面),用户安装完成后,可以在系统设置中修改默认启动的桌面程序
3.2 Launcher.java
Launcher.java是Launcher的启动页面,负责资源初始化和桌面UI创建
3.2.1 onCreate方法
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| |
| LauncherAppState app = LauncherAppState.getInstance(this); |
| mModel = app.getModel(); |
| |
| |
| InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); |
| initDeviceProfile(idp); |
| idp.addOnChangeListener(this); |
| |
| |
| mSharedPrefs = LauncherPrefs.getPrefs(this); |
| mIconCache = app.getIconCache(); |
| |
| |
| mAccessibilityDelegate = createAccessibilityDelegate(); |
| |
| |
| initDragController(); |
| |
| |
| mAllAppsController = new AllAppsTransitionController(this); |
| |
| |
| mStateManager = new StateManager<>(this, NORMAL); |
| |
| |
| mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs); |
| |
| |
| setupViews(); |
| |
| |
| mAppWidgetManager = new WidgetManagerHelper(this); |
| mAppWidgetHolder = createAppWidgetHolder(); |
| mAppWidgetHolder.startListening(); |
| |
| |
| setContentView(getRootView()); |
| ComposeInitializer.initCompose(this); |
| |
| } |
3.2.2 setupViews方法
| protected void setupViews() { |
| |
| inflateRootView(R.layout.launcher); |
| |
| |
| mDragLayer = findViewById(R.id.drag_layer); |
| mFocusHandler = mDragLayer.getFocusIndicatorHelper(); |
| |
| |
| mWorkspace = mDragLayer.findViewById(R.id.workspace); |
| mWorkspace.initParentViews(mDragLayer); |
| mOverviewPanel = findViewById(R.id.overview_panel); |
| mHotseat = findViewById(R.id.hotseat); |
| |
| mHotseat.setWorkspace(mWorkspace); |
| |
| |
| mDragLayer.setup(mDragController, mWorkspace); |
| |
| |
| mWorkspace.setup(mDragController); |
| |
| mWorkspace.lockWallpaperToDefaultPage(); |
| mWorkspace.bindAndInitFirstWorkspaceScreen(); |
| mDragController.addDragListener(mWorkspace); |
| |
| |
| mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar); |
| |
| |
| mAppsView = findViewById(R.id.apps_view); |
| mAppsView.setAllAppsTransitionController(mAllAppsController); |
| |
| |
| mDropTargetBar.setup(mDragController); |
| mAllAppsController.setupViews(mScrimView, mAppsView); |
| |
| |
| if (SHOW_DOT_PAGINATION.get()) { |
| mWorkspace.getPageIndicator().setShouldAutoHide(true); |
| mWorkspace.getPageIndicator().setPaintColor( |
| Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText) |
| ? Color.BLACK |
| : Color.WHITE); |
| } |
| } |
| |
- Workspace:工作区,也是我们常说的桌面区域,包括搜索框,桌面,壁纸
- AppsView:应用程序列表
- Widget:小组件
3.1 Workspace(工作区)


3.2 AppsView(应用程序视图)


四、点击App图标的事件响应
4.1 触发ItemClickHandler的onClick方法
- ItemClickHandler负责处理桌面应用图标的点击事件。
- 桌面图标的点击事件最终会触发ItemClickHandler的onClick方法
- onClick方法最终会触发startAppShortcutOrInfoActivity方法
| |
| |
| |
| public class ItemClickHandler { |
| private static void onClick(View v) { |
| startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher); |
| } |
| |
| |
| private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) { |
| launcher.startActivitySafely(v, intent, item); |
| } |
| } |
4.2 Launcher通知系统启动App
在Launcher.java
的startActivitySafely方法中调用ActivityContext.java
的startActivitySafely方法
| public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) { |
| RunnableList result = super.startActivitySafely(v, intent, item); |
| } |
在ActivityContext.java
的startActivitySafely方法中调用了
| public interface ActivityContext { |
| default RunnableList startActivitySafely( |
| View v, Intent intent, @Nullable ItemInfo item) { |
| if (isShortcut) { |
| |
| startShortcutIntentSafely(intent, optsBundle, item); |
| } |
| } |
| |
| default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) { |
| if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { |
| |
| startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user); |
| } else { |
| |
| ((Context) this).startActivity(intent, optsBundle); |
| } |
| } |
| } |
Android 应用快捷方式(Shortcut)官方文档
最终通过frameworks/base/core/java/android/app/Activity.java 源码地址中的startActivity
方法启动了对应的应用程序。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库