Android 15(API 级别 35)引入了 ApplicationStartInfo
API,可以通过它更深入地了解应用的整个启动过程,包括启动状态、启动阶段所用的时间、在 Application
类被实例化时应用的启动方式等,使开发者能够优化应用启动过程的每一步。
介绍
在以前的 Android 版本中,在应用中确定应用是从冷状态、温状态还是热状态开始的过程很难确定。此外,我们也很难知道您的应用在不同发布阶段所用的时间:创建进程分支、调用 onCreate
、绘制第一帧等。在实例化 Application
类时,您无法得知应用是从广播、content provider、任务(Job)、备份、启动完成(boot complete)、闹钟还是 Activity
启动的。
Android 15 上的 ApplicationStartInfo
API 可提供所有这些功能以及更多其他功能。甚至可以选择将自己的时间戳添加到流程中,以便在一个位置收集时间数据。除了收集指标之外,您还可以使用 ApplicationStartInfo
直接优化应用启动;例如,当应用因广播而启动时,可以避免在 Application
类中实例化界面相关库的高成本。
ApplicationStartInfo
提供了有关应用进程如何启动的详细信息,包括:
获取 ApplicationStartInfo
ApplicationStartInfo
对象可以通过以下方式获取:
1. getHistoricalProcessStartReasons
可以在应用程序启动期间或之后调用。使用此方法,应用程序可以检索有关正在运行的应用程序的启动信息。
ActivityManager.getHistoricalProcessStartReasons 调用示例:
@RequiresApi(35)
private fun getAppStartInfo() {
val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
// 记录列表,按从最近到最不近的顺序排序。
val startInfos = activityManager.getHistoricalProcessStartReasons(0)
startInfos.forEach { info ->
Log.i("ApplicationStartInfo", """
pid=${info.pid}
realUid=${info.realUid}
packageUid=${info.packageUid}
definingUid=${info.definingUid}
user=${info.packageUid}
process=${info.processName}
startupState=${info.startupState}
// 触发进程启动的原因代码
reason=${info.reason}
startType=${info.startType}
launchMode=${info.launchMode}
wasForceStopped=${info.wasForceStopped()}
intent=${info.intent.toString()}
""".trimIndent())
val sb = StringBuilder()
// 整个启动过程中各种阶段的时间戳(以纳秒为单位)
if (info.startupTimestamps.isNotEmpty()) {
sb.append("timestamp: ")
info.startupTimestamps.forEach { (key, value) ->
sb.append("$key=$value ")
}
}
Log.i("ApplicationInfo", sb.toString())
}
}
上例中获取应用启动信息的输出结果:
pid=0
realUid=10203
packageUid=10203
definingUid=10203
user=10203
process=cn.itmob.compose.sample
startupState=2
reason=6
startType=1
launchMode=0
wasForceStopped=false
intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=cn.itmob.compose.sample/.MainActivity bnds=[824,1873][997,2068] }
timestamp: 0=1778473709200 3=1779065303200
2. addApplicationStartInfoCompletionListener
在启动完成时通过回调返回 ApplicationStartInfo
对象,或者在启动完成后请求立即返回。
ActivityManager.addApplicationStartInfoCompletionListener 调用示例:
package cn.itmob.compose.sample
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= 35) {
addStartInfoListener()
}
}
@RequiresApi(35)
private val completionListener = Consumer<ApplicationStartInfo> { info ->
Log.i("ApplicationStartInfo 1", """
pid=${info.pid}
realUid=${info.realUid}
packageUid=${info.packageUid}
definingUid=${info.definingUid}
user=${info.packageUid}
process=${info.processName}
startupState=${info.startupState}
// 触发进程启动的原因代码
reason=${info.reason}
startType=${info.startType}
launchMode=${info.launchMode}
wasForceStopped=${info.wasForceStopped()}
intent=${info.intent.toString()}
""".trimIndent())
val sb = StringBuilder()
// 整个启动过程中各种阶段的时间戳(以纳秒为单位)。
if (info.startupTimestamps.isNotEmpty()) {
sb.append("timestamp: ")
info.startupTimestamps.forEach { (key, value) ->
sb.append("$key=$value ")
}
}
Log.i("ApplicationInfo", sb.toString())
}
@RequiresApi(35)
private fun addStartInfoListener() {
val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
activityManager.addApplicationStartInfoCompletionListener(mainExecutor, completionListener)
}
}
应用启动完成后的输出结果:
pid=0
realUid=10203
packageUid=10203
definingUid=10203
user=10203
process=cn.itmob.compose.sample
startupState=2
reason=6
startType=1
launchMode=0
wasForceStopped=false
intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=cn.itmob.compose.sample/.MainActivity bnds=[824,1873][997,2068] }
timestamp: 0=6370714763300 3=6371095338200
可以通过这些信息分析或优化应用的启动,也可以使用它们来触发特定操作。
总结
通过了解应用启动过程各个步骤以及每步所花费的时间,可以为用户提供更流畅、更快速、更高效的体验。
其他
Android 15 新功能:应用程序启动信息 API
New API: ApplicationStartInfo
Android 15 功能和变更列表
翻译:2024 年 9 月 3 日 Android 15 已发布至 AOSP
Android 15 新功能和 API 详解:Private Space/私密空间功能简介
Android 15 新功能和 API 详解:录屏检测,addScreenRecordingCallback
Android 15 新功能和 API 详解:支持 16 KB 页面大小
Android 15 新功能和 API 详解:更精确的 Intent 解析,UriRelativeFilterGroup 和 UriRelativeFilter