进程和应用生命周期

在大多数情况下,每个 Android 应用都在各自的 Linux 进程中运行。当需要运行应用的一些代码时,系统会为应用创建此进程,并使其保持运行,直到不再需要它且系统需要回收其内存以供其他应用使用。

应用进程的生命周期并不由应用本身直接控制,而是由系统综合多种因素来确定的,比如系统所知道的正在运行的应用部分、这些内容对用户的重要程度,以及系统中可用的总内存量。

应用开发者必须了解不同的应用组件(特别是 ActivityServiceBroadcastReceiver)对应用进程的生命周期有何影响。这些组件使用不当会导致系统在应用进程正执行重要任务时将它终止。

进程生命周期错误的一个常见示例是当 BroadcastReceiver 在其 BroadcastReceiver.onReceive() 方法中接收到一个 Intent 时,它会启动一个线程,然后从该函数返回。一旦返回,系统会认为 BroadcastReceiver 不再处于活动状态,因此不再需要其托管进程(除非其中有其他应用组件处于活动状态)。

因此,系统可以随时终止进程以回收内存,这样会终止在进程中运行的衍生线程。要解决这个问题,通常可以从 BroadcastReceiver 调度 JobService,这样系统就知道进程中有处于活动状态的任务正在进行中。

为了确定在内存不足时应该终止哪些进程,Android 会根据每个进程中运行的组件以及这些组件的状态,将它们放入重要性层次结构。这些进程类型包括(按重要性排序):

  1. 前台进程是用户目前执行操作所需的进程。在不同的情况下,进程可能会因为其所包含的各种应用组件而被视为前台进程。如果以下任一条件成立,则进程会被认为位于前台:
  2. 系统中只有少数此类进程,而且除非内存过低,导致连这些进程都无法继续运行,才会在最后一步终止这些进程。通常,如果发生这种情况,则表示设备已达到内存分页状态,因此必须执行此操作才能使用户界面保持响应。

  3. 可见进程正在进行用户当前知晓的任务,因此终止该进程会对用户体验造成明显的负面影响。在以下条件下,进程将被视为可见:
    • 它正在运行的 Activity 在屏幕上对用户可见,但不在前台(其 onPause() 方法已被调用)。举例来说,如果前台 Activity 显示为一个对话框,而这个对话框允许在其后面看到上一个 Activity,则可能会出现这种情况。
    • 它有一个 Service 正在通过 Service.startForeground()(要求系统将该服务视为用户知晓或基本上对用户可见的服务)作为前台服务运行。
    • 系统正在使用其托管的服务实现用户知晓的特定功能,例如动态壁纸或输入法服务。

    相比前台进程,系统中运行的这些进程数量较不受限制,但仍相对受控。这些进程被认为非常重要,除非系统为了使所有前台进程保持运行而需要终止它们,否则不会这么做。

  4. 服务进程包含一个已使用 startService() 方法启动的 Service。虽然这些进程对用户而言并不直接可见,但它们通常会执行用户关心的事情(例如后台网络数据上传或下载),因此除非内存不足以保留所有前台和可见进程,否则系统会始终让此类进程保持运行状态。

    已经运行了很长时间(例如 30 分钟或更长时间)的服务的重要性可能会降位,以使其进程降至缓存列表。

    您可以使用 setForeground 创建确实需要长时间运行的进程。如果它是需要严格执行时间的周期性进程,则可以通过 AlarmManager 进行调度。如需了解详情,请参阅对长时间运行的工作器的支持。这有助于避免长时间运行的服务因使用过多资源(例如内存泄露)而妨碍系统提供良好的用户体验。

  5. 缓存进程是目前不需要的进程,因此,如果其他地方需要内存等资源,系统可以根据需要自由地终止该进程。在正常运行的系统中,这些是资源管理中涉及的唯一进程。

    运行良好的系统将始终有多个缓存进程可用(为了更高效地切换应用),并根据需要定期终止缓存的应用。只有在非常危急的情况下,系统中的所有缓存进程才会被终止,此时系统必须开始终止服务进程。

    由于系统可以随时终止缓存的进程,因此应用应在处于缓存状态时停止所有工作。如果应用必须执行对用户至关重要的工作,则应使用上述某个 API 从活跃进程状态运行工作。

    缓存的进程通常包含用户当前不可见的一个或多个 Activity 实例(其 onStop() 方法已被调用并返回)。只要在系统终止此类进程时正确实现 Activity 生命周期,就不会影响用户返回该应用时的体验。当关联的 activity 在新进程中重新创建时,它可以恢复之前保存的状态。请注意,如果系统终止进程,系统不一定会调用 onDestroy()。如需了解详情,请参阅 Activity

    从 Android 13 开始,应用进程在进入上述某种活跃生命周期状态之前,可能会获得有限的执行时间或根本无法获得执行时间。

    缓存的进程会保存在列表中。此列表的确切排序政策是平台的实现细节。通常,它会先尝试保留更多有用的进程(比如托管用户的主屏幕应用或用户最后看到的 activity 的进程),再保留其他类型的进程。还可以针对终止进程应用其他政策,例如对允许的进程数量设置硬限制,或限制进程可持续保持缓存状态的时间长短。

在决定如何对进程进行分类时,系统会参考进程中当前活动的所有组件中最重要的级别。如需详细了解这些组件各自对进程和应用的整体生命周期有何影响,请参阅 ActivityServiceBroadcastReceiver 文档。

进程的优先级也可能因从属于进程的其他依赖项而提升。例如,如果进程 A 已通过 Context.BIND_AUTO_CREATE 标记绑定到 Service,或在使用进程 B 中的 ContentProvider,则进程 B 的分类始终至少和进程 A 一样重要。