阅读 513

Android判断冷启动

冷启动是什么

冷启动是一种 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
        }
      }
    }
  }
}
复制代码
文章分类
Android
文章标签