进程和应用生命周期

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

Android 的一个不寻常且基本的功能是,应用程序进程的生命周期不是由应用程序本身直接控制的。相反,它由系统通过应用程序正在运行的已知部分、这些内容对用户的重要性以及系统中可用的总内存量的组合来确定。

应用程序开发者必须了解不同的应用程序组件(特别是ActivityServiceBroadcastReceiver)如何影响应用程序进程的生命周期。不正确地使用这些组件会导致系统在应用程序执行重要工作时将其进程杀死。

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

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

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

  1. **前台进程**是用户当前正在执行的操作所需的进程。各种应用程序组件可以通过不同的方式使其包含的进程被视为前台进程。如果满足以下任何条件,则进程被认为处于前台状态
  2. 系统中永远只有少数几个这样的进程,并且只有在内存非常低以至于即使这些进程也无法继续运行时,才会将其作为最后手段终止。通常,如果发生这种情况,则设备已达到内存分页状态,因此需要执行此操作以保持用户界面响应。

  3. **可见进程**正在执行用户当前知道的工作,因此终止它会对用户体验产生明显的负面影响。在以下情况下,进程被视为可见的
    • 它正在运行一个对用户可见但不在前台的Activity(已调用其onPause()方法)。例如,如果前台Activity显示为一个对话框,该对话框允许之前Activity在其后面可见,则可能会发生这种情况。
    • 它有一个通过Service.startForeground()作为前台服务运行的Service(它要求系统将服务视为用户知道的内容,或者基本上是可见的)。
    • 它正在托管系统用于用户知道的功能的服务,例如动态壁纸或输入法服务。

    系统中运行的这些进程的数量不如前台进程受限,但仍然受到相对控制。这些进程被认为极其重要,除非这样做是保持所有前台进程运行所必需的,否则不会终止它们。

  4. **服务进程**是持有已使用startService()方法启动的Service的进程。虽然这些进程对用户不可见,但它们通常执行用户关心的操作(例如后台网络数据上传或下载),因此系统始终保持这些进程运行,除非没有足够的内存来保留所有前台和可见进程。

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

    需要长时间运行的进程可以使用setForeground创建。如果它是一个需要严格执行时间的周期性进程,则可以通过AlarmManager对其进行调度。有关更多信息,请参阅支持长时间运行的工作器。这有助于避免长时间运行的服务(例如,通过内存泄漏消耗过多资源)阻止系统提供良好用户体验的情况。

  5. **缓存进程**是当前不需要的进程,因此系统可以在需要时随时终止它以满足其他地方的资源(如内存)需求。在正常运行的系统中,这些是唯一涉及资源管理的进程。

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

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

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

    从 Android 13 开始,应用程序进程可能在进入上述任何活动生命周期状态之前,会获得有限的执行时间或根本没有执行时间。

    缓存进程保存在一个列表中。此列表的确切排序策略是平台的实现细节。通常,它会尝试在其他类型的进程之前保留更有用的进程,例如托管用户主应用程序或用户上次看到的最后一个活动的进程。还可以应用其他终止进程的策略,例如设置允许的进程数量的硬限制或限制进程可以持续缓存的时间。

在决定如何对进程进行分类时,系统会根据当前在进程中活动的所有组件中发现的最重要级别做出决定。有关每个组件如何影响进程和应用程序的整体生命周期的更多详细信息,请参阅ActivityServiceBroadcastReceiver文档。

进程的优先级也可能会根据其他进程对其的依赖关系而提高。例如,如果进程 A 已使用Context.BIND_AUTO_CREATE标志绑定到进程 B 中的Service或正在使用ContentProvider,则进程 B 的分类始终至少与进程 A 的分类同等重要。