Android的进程和线程机制(一)——进程

对于一个Android应用程序来说,当它的某个组件开始运行时,此时如果该应用没有其他组件已经在运行,Android系统会为该应用开辟一个新的单线程的Linux进程。默认情况下,该应用的所有组件都会运行在这个进程和线程中,此时这个进程的唯一线程被称作“main”线程即主线程。如果这个应用的其他组件启动时该应用的进程已经存在(即已经有该应用的其他组件在运行),那么新的组件就会在已经存在的进程中启动并使用主线程来执行。然而,我们也可以为同一个应用的不同组件开辟不同的进程,并且可以为每个进程创建额外的线程。

进程

默认情况下,同一个应用的所有组件运行在同一个进程中,这对于多数应用来说是足够的。然而,当我们需要对应用的组件所属的进程作出更细的控制时,我们可以在AndroidManifest.xml文件中进行指定。AndroidManifest.xml文件中,对于每个组件元素——<activity>、<service>、<receiver>和<provider>,都有一个android:process属性可以指定组件的运行进程。通过这个属性,我们可以指定每个组件运行在独立的进程中或部分组件共享一个进程。如果不同应用共享同一个Linux用户ID并且拥有相同的证书,我们还可以通过android:process属性指定跨应用的不同组件共享一个进程。

AndroidManifest.xml文件中,<application>元素也支持android:process属性,我们可以在这里设置一个默认的进程为该应用的所有组件共享。当系统内存不足而其他急需与用户进行交互的进程需要内存时,Android系统可能会在某一时刻选择关闭一些进程以释放资源为新进程服务。此时,运行在这些进程里的组件也会被销毁,当再次启动这些组件时此时会开辟新的进程。这一点是我们需要注意的,之前的数据就会丢失。至于系统会选择哪些进程来杀死,这取决于这些进程对于用户的重要性,系统会计算这个权重来排序。比如,相对于当前尚有处于可视状态的Activity的进程来说,那些只有组件在后台运行的进程就会更容易被系统杀死。因此,是否要终止一个进程是取决于该进程当前运行的组件的状态。


进程的生命周期
在资源充足的情况下,Android系统会尽量维系一个应用进程的存活时间,但系统总会有资源紧张的时候,当有新的更重要的进程申请资源的时候系统就会移除掉一些相对来说不再重要的旧进程以释放资源腾出空间给新的更重要的进程来使用。在决定哪些进程要被杀死,哪些进程要被保留时,系统会根据每个进程中所运行的组件及其状态来计算一个权重值并进行排序,那么那些重要性最低的进程就会首先被移除掉,然后是次低重要性的进程,以此类推,直至释放出了必需的资源。进程重要性的级别被划分为5个等级。下面按照从高到低依次进行详细说明(重要性最高的进程将最后被杀死):
前台进程
所谓前台进程,指的是当前正在与用户进行交互的进程。当下面的条件满足任何一个时,该进程就会被认为是前台进程:
1、该进程有一个Activity正在与用户进行交互,即该Activity正处于onResume()状态时;
2、该进程有一个Service与当前用户正在进行交互的Activity绑定;
3、该进程有一个Service正在前台运行,即该Service的startForeground()方法被调用;
4、该进程有一个Service的生命周期回调方法(onCreate()、onStart()或onDestroy())正在被调用;
5、该进程有一个BroadcastReceiver正在执行其onReceive()方法。
一般来说,任何一个时间点上系统运行的前台进程都不会很多。而这些前台进程除非是在系统内存严重不足甚至到了不能满足这些前台进程运行的情况下才会被杀死。它们是系统杀死的最后选择。一般来说,这种情况一般发生在系统已经到了内存分页的状态,只有杀死一部分前台进程才能保证对用户的操作作出响应。

可视进程
所谓可视进程,指的是虽然当前没有处于前台的组件但仍然能够影响到呈现给用户的视图的进程。以下条件满足任何一个时,该进程就可以被认为是可视进程:
1、该进程有一个Activity虽然不在前台,但用户此时仍然能够看到,即该Activity处于onPause()状态,比如当前直接与用户交互的Activity打开了一个对话框,则该Activity就会被对话框罩住,但仍然是可视的;
2、该进程有一个Service与一个可视的或前台的Activity绑定。
可视进程对系统来说也是非常重要的,除非只有杀死它才能保证所有的前台进程能够正常运行时系统才会去杀死可视进程。
服务进程
所谓服务进程,指的是运行着一个通过startService()方法启动的Service组件而尚未成为可视进程和前台进程的进程。尽管服务进程并未直接与用户界面相关联,但它们所执行的动作却是用户关心的(比如在后台播放音乐或是下载网络数据),因此除非没有足够的内存来支撑这些服务进程以及所有的前台进程和可视进程的运行系统才会杀死服务进程。
后台进程
所谓后台进程,指的是拥有一个当前对用户不可视的Activity在运行(即该Activity处于onStop()状态)的进程。此类进程不再直接影响用户界面,系统可在前台进程、可视进程或服务进程需要资源时系统内存不足的情况下随时杀死后台进程。通常系统会有很多后台进程在运行,这些后台进程被系统以一个LRU(最近最少使用)列表所维护着以确保最后与用户进行交互的Activity所在的进程被最后杀死。如果正确地实现了一个Activity的各个生命周期方法并保存了当前的状态数据的话,那么杀死该Activity所在的进程就不会对用户界面产生任何可视的影响。因为当用户再次返回到该Activity时,它会恢复自己的所有可视状态数据。

空进程
所谓空进程,指的是没有任何活跃的组件在运行的进程。此类进程存活的唯一目的是为了缓存的考虑,以在下次该进程的某个组件运行时可以快速启动。系统会在进程缓存和内核缓存之间作出系统总体资源的平衡以决定是否杀死空进程。基于进程当前活跃的组件的重要性,Android系统会以组件的最高重要性为准来标识该进程的重要性。比如,如果一个进程拥有一个Service和一个可视的Activity,那么该进程就会被标识为可视进程而不是服务进程。
此外,一个进程的重要性也可能会被提升如果有其他进程依赖于它,即该进程是服务于其他进程的,因此不可能会比它所服务的进程的重要性低。比如,进程A中的一个ContentProvider组件服务于进程B的客户端,或进程A中的一个Service组件与进程B中的一个组件绑定,则进程A的重要性最低会与进程B的重要性相等。


因为运行Service组件的进程重要性要高于运行后台Activity的进程,因此对于一个Activity来说,与其开启一个工作线程来执行一个常驻操作不如启动一个Service来做这件事,特别是在该操作的生命周期要长于这个Activity的时候。比如,一个需要上传图片的Activity应该启动一个Service来执行这个上传操作,这样即使用户离开了该Activity上传操作也能继续在后台执行。使用Service组件来执行一些耗时的操作能够保证这个操作最少拥有服务进程的优先级,而不用管Activity界面的状态如何。这也是为什么BroadcastReceiver应该使用Service而不是开启一个线程执行耗时操作的同样的原因。

Android的进程和线程机制(一)——进程

上一篇:android动画的实战篇------乐动力旋转动画


下一篇:android 关于底部控件遮挡上面list控件的解决办法