如果我们 post 一条消息并且在该消息运行时没有创建任何 Activity ,那么我们就知道这不是冷启动,即使 Activity 最终在 20 秒后启动。
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
var firstActivityCreated = false
registerActivityLifecycleCallbacks(object :
ActivityLifecycleCallbacks {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
if (firstActivityCreated) {
return
}
firstActivityCreated = true
}
})
Handler().post {
if (firstActivityCreated) {
// TODO Report cold start
}
}
}
}
复制代码
使用这种方法,我们必须等待 Activity 启动或消息运行,然后才能知道应用程序启动是否是冷启动。 有时从 Application.onCreate() 中知道这一点会很有用。 例如,我们可能希望异步预加载资源以优化冷启动:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
if (isColdStart()) {
preloadDataForUiAsync()
}
}
}
复制代码
进程重要性
虽然没有 Android API 可以知道进程为什么启动,但有一个 API 可以知道进程为什么仍在运行:RunningAppProcessInfo.importance,我们可以从 ActivityManager.getMyMemoryState() 中读取。 根据进程和应用程序生命周期文档:
为了确定哪些进程在内存不足时应该被杀死,Android 根据其中运行的组件和这些组件的状态将每个进程置于“重要性层次结构”中。 在决定如何对进程进行分类时,系统将根据在流程中当前 Activity 的所有组件中找到的最重要级别做出决定。
当进程开始时,我们可以检查它的重要性。 如果重要性为 IMPORTANCE_FOREGROUND,则必须是冷启动:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
if (isForegroundProcess()) {
preloadDataForUiAsync()
}
}
private fun isForegroundProcess(): Boolean {
val processInfo = ActivityManager.RunningAppProcessInfo()
ActivityManager.getMyMemoryState(processInfo)
return processInfo.importance == IMPORTANCE_FOREGROUND
}
}
复制代码
用数据确认
我在示例应用程序中使用这两种方法实现了冷启动检测,并获得了相同的结果。 然后,我将检测代码添加到具有足够安装量的生产应用程序中,以提供有意义的结果。
-
当启动重要性为 100 时,总会在第一次 post 之前创建一个 Activity 。 当一个 Activity 在第一次 post 之前创建时,97.4% 的时间重要性为 100。
-
当启动重要性为 400 时,几乎不会在第一次 post 之前创建 Activity。 几乎从不也不是从不,仍然有足够多的案例在首次 post 之前创建 Activity ,2.4% 的时间重要性为 400。
对重要性为 400 的 2.4% 最可能的解释是那些不是冷启动,但是系统几乎在进程开始后立即收到启动 Activity 的查询,就在运行 Application.onCreate() 时,但在我们有机会发布我们第一个post。
编辑:我在第一次 post 后记录了重要性,并将其与应用程序启动时的重要性进行了比较。 我的数据显示,74% 的应用程序在首次 post 之前创建 Activity 的地方启动,并且启动进程重要性不是 100,如果进程重要性在首次发布后更改为 100。 这似乎证实了系统决定在应用程序已经开始启动后启动 Activity 的理论。
结论
我们可以结合上一篇文章的发现来准确确定冷启动。 冷启动:
-
在应用程序启动时进程重要性为 IMPORTANCE_FOREGROUND。
-
在第一个 post 出队之前创建了第一个 Activity 。
-
具有使用空包创建的第一个 Activity 。
这是更新后的代码:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
if (isForegroundProcess()) {
var firstPostEnqueued = true
Handler().post {
firstPostEnqueued = false
}
registerActivityLifecycleCallbacks(object :
ActivityLifecycleCallbacks {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
unregisterActivityLifecycleCallbacks(this)
if (firstPostEnqueued && savedInstanceState == null) {
// TODO Report cold start
}
}
})
}
}
private fun isForegroundProcess(): Boolean {
val processInfo = ActivityManager.RunningAppProcessInfo()
ActivityManager.getMyMemoryState(processInfo)
return processInfo.importance == IMPORTANCE_FOREGROUND
}
}
复制代码