Skip to content

Latest commit

 

History

History
51 lines (29 loc) · 6.47 KB

进程和应用程序的生命周期.md

File metadata and controls

51 lines (29 loc) · 6.47 KB

进程和应用程序的生命周期

原文(英文)地址

在大多数情况下,每一个Android应用程序都是一个独立的Linux进程,这个进程在一些代码需要被运行时被创建,一直存活到该进程不再被需要且系统需要清理该进程以腾出更多的内存给其他应用程序使用。

Android应用程序一个基本的、不同一般程序的特性是一个Android应用程序的生命周期不能被该应用程序直接控制,相反的,它的生命周期由系统决定,系统根据系统知道正在运行的应用程序部分的组合,这些应用程序对用户的重要性以及系统中可用的总体内存来确定。

开发人员应该了解不同应用组件(特别是Activity、Service、BroadCastReceiver)对应用进程生命周期的影响。不正确地使用这些组件可能会导致系统杀死正在执行重要工作的应用进程。

关于进程生命周期导致bug的一个很常见的例子是BroadCastReceiver,当它在自己的onReceive()方法中接收到Intent并启动一个线程后return,一旦return,系统会认为BroadCastReceiver不再处于活动状态,因此不再需要托管该进程(除非其他应用程序组件依然处于活动状态),系统随时可能会终止进程以回收内存,这样就会终止之前在进程中onReceive()启动的线程,会破坏该线程中原本应该执行的工作。这个文艺的解决方案通常是从BroadCastReceiver中使用一个JobService,这样系统就可以知道该进程中仍有未完成的工作。

为了确定哪些进程在内存紧张的时候应该被销毁,Android根据进程中正在运行的组件以及这些组件的状态将进程划分为不同的"重要等级",按照重要程度依次有以下等级:

前台进程(foreground process)

前台进程是用户当前正在执行的操作所必需的进程。各种应用程序组件可以使其宿主进程以不同的方式被视为前台进程。如果满足以下任何条件,则认为进程处于前台:

  • 进程中有一个用户正在关注的Activity在运行(该Activity的onResume()方法已经被调用)
  • 进程中有一个BroadCastReceiver正在被运行(该BroadCastReceiver的onReceive()方法正在被执行)
  • 进程中有一个Service且其某一个回调方法正在被执行(Service.onCreate(),Service.onStart(),Service.onDestroy())

系统中只会有数量很少的这样的进程,如果内存太低甚至这些进程都不能继续运行,这些只会作为最后的进程被杀死。通常,此时,设备已达到内存分页状态,因此需要杀死这些进程以保持用户界面正常响应。

可见进程(visible process)

可见进程正在进行用户当前意识到的工作,因此杀死它会对用户体验产生明显的负面影响。符合以下条件的进程即为可见进程:

  • 进程中有Activity对用户可见但是不在前台(对应Activity的onPause()已经被调用)。比如Activity被DIalog部分覆盖。
  • 进程中通过Service.startForground()启动了在前台运行的Service(这要求系统将服务视为用户可意识到的或基本上对用户可见的东西)
  • 进程正在托管系统用于用户知道的特定功能的服务,例如动态壁纸,输入法服务等。

在系统中运行的可见进程的数量比前台进程更少,但仍然是相对受控的。这些进程被认为是非常重要的,除非为了保持所有前台进程运行,否则不会被杀死这些可见进程。

服务进程(service process)

服务进程是一个持有使用startService()方法启动的服务的进程。虽然用户无法直接看到这些进程,但它们通常是用户关心的事情(例如后台网络数据上传或下载),因此系统将始终保持此类进程运行,除非没有足够的内存来保留所有前台进程和可见进程。 已经运行了很长时间(例如30分钟或更长时间)的Service可能会降级,以允许其进程被添加到下面描述的缓存LRU列表。这有助于避免出现内存泄漏或其他原因比如长时间运行服务占用大量RAM而导致系统无法有效使用缓存进程的情况。

缓存进程(cached process)

缓存进程是当前不需要的进程,因此当其他地方需要内存时,系统可以根据需要自由地终止缓存进程。在正常运行的系统中,这些是内存管理中涉及的唯一进程:运行良好的系统将始终具有多个缓存进程(用于在应用程序之间进行更有效的切换),并根据需要定期终止最旧的进程。只有在非常关键(且不可取)的情况下,系统才会杀死所有缓存进程,并且必须开始终止服务进程。 这些进程通常包含一个或多个当前对用户不可见的Activity实例(已调用并返回onStop()方法)。如果他们正确地实现了他们的活动生命周期(请参阅Activity以获取更多详细信息),当系统杀死此类进程时,它不会影响用户返回该应用程序时的体验:它可以在重新创建关联Activity时恢复以前保存的状态一个新的进程。

这些进程保存在伪LRU列表(pseudo-LRU list)中,列表中的最后一个进程是第一个被回收内存的进程。在此列表上排序的确切策略是平台的实现细节,但通常它会尝试在其他类型的进程之前保留更多有用的进程(一个托管用户的主应用程序,他们看到的最后一个Activity等)。还可以应用其他用于终止进程的策略:对允许的进程数量的硬限制,对进程可以持续缓存的时间量的限制等。

总结

在决定如何对进程进行分类时,系统将根据进程中当前起作用(活动)的所有组件中找到的最重要级别做出决策。有关每个组件如何对流程的整个生命周期做出贡献的更多详细信息,请参阅ActivityServiceBroadcastReceiver文档。每个类的文档都更详细地描述了它们如何影响其应用程序的整个生命周期。

还可以基于进程对其具有的其他依赖性来增加进程的优先级。例如,如果进程A已使用Context.BIND_AUTO_CREATE标志绑定到Service,或者正在进程B中使用ContentProvider,则进程B的分类将始终至少与进程A一样重要。