进程和应用生命周期

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

Android 的一项不同基本功能是,应用进程的生命周期由应用本身直接控制。而是由系统综合考虑系统所知道正在运行的应用部分、这些内容对用户的重要性以及系统中可用的总体内存量来决定的。

应用开发者必须了解不同的应用组件(尤其是 ActivityServiceBroadcastReceiver)对应用进程的生命周期有何影响。未正确使用这些组件可能会导致系统在应用进程执行重要工作时终止它。

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

因此,系统可以随时终止进程以回收内存,并且这样做会终止进程中运行的衍生线程。解决此问题的方案通常是从 BroadcastReceiver 调度 JobService,以便系统知道进程中有正在进行的工作。

为了确定在内存不足时终止哪些进程,Android 会根据每个进程中运行的组件和这些组件的状态,将这些进程置于重要性层次结构中。按照重要性,这些进程类型包括:

  1. 前台进程是用户当前执行操作所必需的进程。因各种应用组件,导致其包含的进程被视作前台进程的方式也有所不同。如果以下任一条件成立,则进程会被视为前台进程:
  2. 系统中只有少数这样的进程,只有在内存不足以致这些进程无法继续运行时,才会在万不得已时终止这些进程。通常,如果发生这种情况,设备已达到内存分页状态,因此需要执行此操作才能使界面保持迅速响应。

  3. 可见进程正在执行用户当前知晓的工作,因此终止该进程会对用户体验产生明显的负面影响。在以下条件下,进程被视为可见:
    • 它运行的 Activity 在屏幕上对用户可见,但不在前台(其 onPause() 方法已被调用)。例如,如果前景 Activity 显示为一个对话框,使上一个 Activity 可在其后显示,就可能会发生这种情况。
    • 它具有一个 Service,它通过 Service.startForeground() 作为前台服务运行(这会要求系统将该服务视为用户知晓或实质上被视为可见)。
    • 它托管着一项服务,系统正在使用该服务实现用户知晓的特定功能,例如动态壁纸或输入法服务。

    与前台进程相比,系统中运行的这些进程的数量没那么受限,但仍然相对受控。这些进程被视为极其重要,不会被终止,除非必须这样做以使所有前台进程保持运行状态。

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

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

    可以使用 setForeground 创建需要长时间运行的进程。如果是需要严格执行时间的定期进程,可以通过 AlarmManager 进行调度。如需了解详情,请参阅对长时间运行的 worker 的支持。 这有助于避免长时间运行的服务使用过多资源(例如,通过泄露内存)阻止系统提供良好的用户体验。

  5. 缓存进程是当前不需要的进程,因此当其他位置需要诸如内存等资源时,系统会根据需要随意终止该进程。在正常运行的系统中,这些是资源管理中涉及的唯一进程。

    运行良好的系统始终会有多个缓存进程可用,以便在应用之间高效切换,并可根据需要定期终止缓存的应用。只有在非常关键的情况下,系统才会达到所有缓存进程都会终止的程度,并且必须开始终止服务进程。

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

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

    从 Android 13 开始,在进入上述某种活跃生命周期状态之前,应用进程可能只会收到有限的执行时间或者没有执行时间。

    缓存的进程会保存在列表中。此列表的确切排序政策是平台的实现细节。通常,它会尝试保留更实用的进程,例如托管用户的主屏幕应用或用户上次看到的 activity 的进程,然后运行其他类型的进程。您也可以应用终止进程的其他政策,例如对允许的进程数量设置硬性限制或限制进程可以持续缓存的时长。

在决定如何对进程进行分类时,系统会基于进程中当前活动的所有组件中最重要的级别做出决策。请参阅 ActivityServiceBroadcastReceiver 文档,详细了解其中每个组件对进程和应用的总体生命周期有何影响。

进程的优先级也可能会根据进程对它的其他依赖项而提高。例如,如果进程 A 已使用 Context.BIND_AUTO_CREATE 标志绑定到 Service,或在进程 B 中使用 ContentProvider,则进程 B 的分类总是至少与进程 A 一样重要。