冷启动是什么
冷启动是一种 Activity 启动,其中应用程序进程从头开始响应启动 Activity 的意图。 根据App启动时间文档:
这种类型的启动在最小化启动时间方面提出了最大的挑战,因为系统和应用程序比其他启动状态有更多的工作要做。
我们建议始终基于冷启动的假设进行优化。 这样做也可以提高温启动和热启动的性能。
为了优化冷启动,我们需要对其进行测量,这意味着我们需要监控生产中的冷启动时间。
传统方法
如果第一个 Activity 是在应用程序启动后的一分钟内创建的,大多数应用程序和库会报告冷启动。 它看起来像这样:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
val appCreateMs = SystemClock.uptimeMillis()
var firstActivityCreated = false
registerActivityLifecycleCallbacks(object :
ActivityLifecycleCallbacks {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
if (firstActivityCreated) {
return
}
firstActivityCreated = true
val activityCreateMs = SystemClock.uptimeMillis()
if (activityCreateMs - appCreateMs < 60_000) {
// TODO Report cold start
}
}
})
}
}
复制代码
不幸的是,这种方法还包括应用进程开始响应广播接收器、内容提供者查询或启动服务,然后有时在第一分钟内启动 Activity 的情况。我们应该将这些情况从冷启动监控中排除,以避免歪曲我们的结果。
-
当应用程序进程启动时,它会调用 ActivityThread.main(),它会在 system_server 进程中对 ActivityManagerService.attachApplication() 进行阻塞 IPC 调用。
-
system_server 进程对应用进程中的 ActivityThread.bindApplication() 进行 IPC 调用,该调用将 BIND_APPLICATION 消息排入主线程消息队列。
-
然后,对于需要启动的每个 Activity ,system_server 进程对应用进程中的 ActivityThread.scheduleTransaction() 进行 IPC 调用,将 EXECUTE_TRANSACTION 消息排入主线程消息队列。
-
当对 ActivityManagerService.attachApplication() 的 IPC 调用完成后,ActivityThread.main() 然后调用 Looper.loop(),它会永远循环,处理发布到其 MessageQueue 的消息。
-
处理的第一条消息是 BIND_APPLICATION,它调用 ActivityThread.handleBindApplication(),后者调用 Application.onCreate()。
-
下一条处理的消息是 EXECUTE_TRANSACTION,它调用 TransactionExecutor.execute() 来启动活动。
这意味着在 Application.onCreate() 中,主线程消息队列已经有 EXECUTE_TRANSACTION 消息入队。 如果我们从 Application.onCreate() 发布一条新消息,它将在 EXECUTE_TRANSACTION 之后执行,因此在创建 Activity 之后。 如果我们发布一条消息并且在执行时没有创建 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
}
}
}
}
复制代码
温启动
根据App启动时间文档:
有许多潜在的状态可以被认为是温启动。 例如:
用户退出应用程序,然后重新启动它。 该过程可能会继续运行,但应用程序必须通过调用 onCreate() 从头开始重新创建 Activity。
系统从内存中杀死应用程序,然后用户重新启动它。 进程和 Activity 需要重新启动,但任务可以从传递给 onCreate() 的已保存实例状态包中受益。
因此,如果 Activity 是使用保存的实例状态包创建的,则不应将其视为冷启动。 但是,由于进程需要重新启动,因此除了创建 Activity 之外,还有很多工作要做。 让我们称之为一个温启动。
我们可以更新我们的代码以考虑到这一点:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
var firstActivityCreated = false
var hasSavedState = false
registerActivityLifecycleCallbacks(object :
ActivityLifecycleCallbacks {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
if (firstActivityCreated) {
return
}
firstActivityCreated = true
hasSavedState = savedInstanceState != null
}
})
Handler().post {
if (firstActivityCreated) {
if (hasSavedState) {
// TODO Report lukewarm start
} else {
// TODO Report cold start
}
}
}
}
}
复制代码