进程和应用生命周期

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

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

应用开发者务必了解不同的应用组件(尤其是 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进行调度。有关更多信息,请参阅支持长时间运行的 Worker。这有助于避免长时间运行的服务(例如,通过内存泄漏)使用过多资源而阻止系统提供良好的用户体验的情况。

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

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

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

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

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

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

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

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