在大多数情况下,每个 Android 应用都在自己的 Linux 进程中运行。当应用的某些代码需要运行时,系统会为应用创建此进程,并使其保持运行状态,直到系统需要回收其内存供其他应用使用,并且不再需要它时。
Android 的一个不同寻常且基础性的特性是,应用进程的生命周期**并非**由应用本身直接控制。相反,它由系统根据系统已知的应用正在运行的部分、这些部分对用户的重要性以及系统中可用的总内存量综合决定。
应用开发者了解不同的应用组件(特别是 Activity
、Service
和 BroadcastReceiver
)如何影响应用进程的生命周期非常重要。**不正确地使用这些组件可能导致系统在应用执行重要工作时终止其进程。**
进程生命周期 bug 的一个常见示例是 BroadcastReceiver
,它在 BroadcastReceiver.onReceive()
方法中收到 Intent
时启动一个线程,然后从该函数返回。一旦返回,系统就认为 BroadcastReceiver
不再处于活跃状态,并且除非其中有其他应用组件处于活跃状态,否则其宿主进程不再需要。
因此,系统可以随时终止该进程以回收内存,并在这样做时终止在该进程中运行的已启动线程。此问题的解决方案通常是从 BroadcastReceiver
调度 JobService
,以便系统知道该进程中正在进行活跃工作。
为了确定在内存不足时要终止哪些进程,Android 根据其中运行的组件及其状态将每个进程放入重要性层次结构中。按重要性顺序,这些进程类型是:
- **前台进程**是用户当前正在执行任务所必需的进程。各种应用组件可以通过不同方式使其包含进程被视为前台进程。如果满足以下任何条件,则进程被视为处于前台:
- 它正在运行用户正在与之交互的屏幕顶部的
Activity
(其onResume()
方法已被调用)。 - 它有一个当前正在运行的
BroadcastReceiver
(其BroadcastReceiver.onReceive()
方法正在执行)。 - 它有一个当前正在执行其回调之一中的代码的
Service
(Service.onCreate()
、Service.onStart()
或Service.onDestroy()
)。
- 它正在运行用户正在与之交互的屏幕顶部的
- **可见进程**正在执行用户当前知晓的工作,因此终止它会对用户体验产生明显的负面影响。在以下条件下,进程被视为可见:
- 它正在运行用户在屏幕上可见但不在前台的
Activity
(其onPause()
方法已被调用)。例如,如果前台Activity
显示为对话框,允许在其后面看到之前的Activity
,则可能会发生这种情况。 - 它有一个正在作为前台服务运行的
Service
,通过Service.startForeground()
(它要求系统将该服务视为用户知晓的事物,或者基本上就像它可见一样)。 - 它托管着系统用于用户知晓的特定功能的服务,例如动态壁纸或输入法服务。
系统中运行的此类进程数量不如前台进程受限,但仍然相对受控。这些进程被认为极其重要,除非为了保持所有前台进程运行而必需,否则不会被终止。
- 它正在运行用户在屏幕上可见但不在前台的
- **服务进程**是持有已通过
startService()
方法启动的Service
的进程。尽管这些进程对用户不直接可见,但它们通常正在执行用户关心的任务(例如后台网络数据上传或下载),因此系统始终保持此类进程运行,除非内存不足以保留所有前台和可见进程。已长时间运行(例如 30 分钟或更长时间)的服务可能会被降级,以使其进程降至缓存列表。
需要长时间运行的进程可以使用
setForeground
创建。如果它是需要严格执行时间的周期性进程,则可以通过AlarmManager
进行调度。有关详细信息,请参阅对长时间运行的 worker 的支持。这有助于避免长时间运行的服务(例如,通过内存泄漏)使用过多资源,从而阻止系统提供良好的用户体验的情况。 - **缓存进程**是当前不需要的进程,因此当其他地方需要内存等资源时,系统可以根据需要自由终止它。在正常运行的系统中,这些是唯一涉及资源管理的进程。
一个运行良好的系统始终有多个缓存进程可用,以便在应用程序之间高效切换,并根据需要定期终止缓存的应用程序。只有在非常关键的情况下,系统才会达到所有缓存进程都被终止并且必须开始终止服务进程的地步。
由于缓存进程可以随时被系统终止,因此应用程序在缓存状态下应停止所有工作。如果应用程序必须执行用户关键的工作,则应使用上述 API 之一从活动进程状态运行工作。
缓存进程通常包含一个或多个当前对用户不可见的
Activity
实例(其onStop()
方法已调用并返回)。如果它们在系统终止此类进程时正确实现了其Activity
生命周期,则在返回该应用程序时不会影响用户体验。当关联的活动在新进程中重新创建时,它可以恢复先前保存的状态。请注意,在进程被系统终止的情况下,不保证调用onDestroy()
。有关详细信息,请参阅Activity
。从 Android 13 开始,应用进程在进入上述活动生命周期状态之一之前,可能会获得有限或不获得执行时间。
缓存进程保留在列表中。此列表的确切排序策略是平台的实现细节。通常,它会尝试在其他类型的进程之前保留更有用的进程,例如托管用户主应用或用户上次看到的活动的进程。还可以应用其他终止进程的策略,例如对允许的进程数量设置硬限制或限制进程可以持续缓存的时间。
系统中此类进程的数量通常很少,并且只有在内存极度不足,甚至这些进程也无法继续运行时,才会作为最后手段被终止。通常,如果发生这种情况,设备已达到内存分页状态,因此此操作是保持用户界面响应所必需的。
在决定如何对进程进行分类时,系统根据在进程中当前活动的所有组件中发现的最重要级别做出决定。有关这些组件如何影响进程和应用程序的整体生命周期的更多详细信息,请参阅 Activity
、Service
和 BroadcastReceiver
文档。
进程的优先级也可能因其对其他进程的依赖而提高。例如,如果进程 A 已使用 Context.BIND_AUTO_CREATE
标志绑定到进程 B 中的 Service
,或者正在使用进程 B 中的 ContentProvider
,则进程 B 的分类始终至少与进程 A 的分类一样重要。