应用启动¶
随着系统服务启动接近尾声,应用开始被激活,包括主屏幕。正如我在第 2 章所解释的,活动管理器通过发送类型为 Intent.CATEGORY_HOME 的 intent 结束其初始化,这会导致启动器应用启动并显示主屏幕。但这只是故事的一部分。系统服务的启动实际上会导致相当多的应用启动。以下是刚启动的 2.3/Gingerbread 模拟器镜像上 ps 命令的部分输出:
# ps
...
root 32 1 60832 16240 c009b74c afd0b844 S zygote
media 33 1 17976 1056 ffffffff afd0b6fc S /system/bin/mediaserver
bluetooth 34 1 1256 220 c009b74c afd0c59c S /system/bin/dbus-daemon
root 35 1 812 232 c02181f4 afd0b45c S /system/bin/installd
keystore 36 1 1744 212 c01b52b4 afd0c0cc S /system/bin/keystore
root 38 1 824 268 c00b8fec afd0c51c S /system/bin/qemud
shell 40 1 732 200 c0158eb0 afd0b45c S /system/bin/sh
root 41 1 3364 168 ffffffff 00008294 S /sbin/adbd
system 61 32 124096 26352 ffffffff afd0b6fc S system_server
app_19 113 32 80336 17400 ffffffff afd0c51c S com.android.inputmethod.latin
radio 121 32 87112 17972 ffffffff afd0c51c S com.android.phone
system 122 32 73160 18452 ffffffff afd0c51c S com.android.systemui
app_26 132 32 76608 20812 ffffffff afd0c51c S com.android.launcher
app_1 169 32 85368 20584 ffffffff afd0c51c S android.process.acore
app_12 234 32 70752 15748 ffffffff afd0c51c S com.android.quicksearchbox
app_8 242 32 73108 16908 ffffffff afd0c51c S android.process.media
app_10 266 32 70928 16572 ffffffff afd0c51c S com.android.providers.calendar
app_29 300 32 72764 17484 ffffffff afd0c51c S com.android.email
app_18 315 32 70272 15428 ffffffff afd0c51c S com.android.music
app_22 323 32 69712 15220 ffffffff afd0c51c S com.android.protips
app_3 335 32 71432 16756 ffffffff afd0c51c S com.cooliris.media
...
所有具有 Java 风格进程名的进程实际上都是在系统启动时无需任何用户干预而自动启动的应用。各种系统机制根据它们各自清单文件的内容导致这些应用启动。
这是一个可喜的变化,因为与应用激活控制相比,控制启动所需的内部工作要比控制我们上面看到的启动的许多其他方面少得多。相反,这完全取决于为与 AOSP 打包而精心制作的应用。当然,在某些情况下,你会想要修改一个库存应用以使其行为或启动方式不同,但至少我们进入了应用世界,在这个世界里,功能更加松散耦合,文档也更易于获取。
这就引出了我们接下来要讨论的内容:什么触发了库存应用被激活。
输入法¶
最早启动的应用类型之一是输入法。输入法管理器服务(Input Method Manager Service)的构造函数会遍历并激活所有具有 android.view.InputMethod intent 过滤器的应用服务。例如,这就是 LatinIME 应用(作为 com.android.inputmethod.latin 进程运行)被激活的方式。
正如你可以通过阅读 Android 开发者博客上的"创建输入法"博客文章所看到的,输入法实际上是精心设计的服务。
持久化应用¶
在其清单文件的 <application> 元素的 android:persistent="true" 属性的应用将在启动时由活动管理器自动生成。事实上,如果这样的应用死亡了,活动管理器也会自动重新启动它。
正如我之前解释的,与普通应用不同,标记为持久化的应用不受活动管理器的生命周期管理。相反,它们在整个系统生命周期中保持活力。这允许使用此类应用来实现特殊功能。例如,作为 com.android.systemui 和 com.android.phone 进程运行的状态栏和电话应用就是持久化应用。
尽管应用开发文档确实解释了 android:persistent 的作用,但该属性的使用保留给在 AOSP 内构建的应用。
主屏幕¶
通常只有一个主屏幕应用,它对 Intent.CATEGORY_HOME intent 做出反应,该 intent 由活动管理器在系统服务启动结束时发送。development/samples/Home/ 中有一个示例主应用,但实际激活的主应用在 packages/apps/Launcher2/ 中。以下是 2.3/Gingerbread 中启动器的主 activity 及其 intent 过滤器(4.2/Jelly Bean 的基本相同):
<activity
android:name="com.android.launcher2.Launcher"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/Theme"
android:screenOrientation="nosensor"
android:windowSoftInputMode="stateUnspecified|adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
</intent-filter>
</activity>
显然,如果你想像 Launcher2 一样启动一个自定义应用作为主屏幕,你需要移除 Launcher2 并添加你自己的、能够对该相同 intent 做出反应的应用。如果有多个应用对该 intent 做出反应,用户将获得一个对话框,询问他们想要使用哪个主屏幕。
请注意,这个 intent 不仅在启动时发送。根据系统的状态,活动管理器将在需要将主屏幕带到前台时发送此 intent。
BOOT_COMPLETED intent¶
活动管理器还会在启动时广播 Intent.BOOT_COMPLETED intent。这是一个应用常用来接收系统已完成启动通知的 intent。AOSP 中的许多库存应用实际上依赖这个 intent,如媒体提供者(Media Provider)、日历提供者(Calendar provider)、Mms 应用和电子邮件应用。以下是 2.3/Gingerbread 中媒体提供者使用的广播接收器及其 intent 过滤器(4.2/Jelly Bean 的非常相似):
<receiver android:name="MediaScannerReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<data android:scheme="file" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
<data android:scheme="file" />
</intent-filter>
</receiver>
为了接收此 intent,应用必须明确请求相应的权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
APPWIDGET_UPDATE intent¶
除了应用之外,应用小组件服务(App Widget Service)——它本身是一个系统服务——注册自己接收 Intent.BOOT_COMPLETED。它使用收到此 intent 作为触发器,通过发送 Intent.APPWIDGET_UPDATE 来激活系统中所有的应用小组件。因此,如果你在你的应用中开发了一个应用小组件,你的代码将在此时被激活。关于如何编写你自己的应用小组件的更多信息,请参阅 Android 开发者文档中的应用小组件部分。
AOSP 中有多个库存应用有应用小组件,如快速搜索框(Quick Search Box)、音乐、提示和媒体。例如,以下是快速搜索框在其清单文件中声明的应用小组件:
<receiver android:name=".SearchWidgetProvider"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info" />
</receiver>