Android进程优先级

来源:互联网 发布:万税 知乎 编辑:程序博客网 时间:2024/06/14 00:45

Android 进程层次

这里写图片描述

前台进程(Foreground process)

前台进程是用户当前做的事所必须的进程,如果满足下面各种情况中的一种,一个进程被认为是在前台:

1.进程持有一个正在与用户交互的Activity

2.进程持有一个Service,这个Service至少满足这几种状况之一:
①Service与用户正在交互的Activity绑定。
②Service是在前台运行的,即它调用了 startForeground()
③Service正在执行它的生命周期回调函数(onCreate(), onStart(), or onDestroy())。

3.进程持有一个BroadcastReceiver,这个BroadcastReceiver正在执行它的 onReceive() 方法。

可见进程(Visible process)

如果一个进程不含有任何前台的组件,但仍可被用户在屏幕上所见。当满足如下任一条件时,进程被认为是可见的:

1.进程持有一个Activity,这个Activity不在前台,但是仍然被用户可见(处于onPause()调用后又没有调用onStop()的状态,比如,前台的activity打开了一个对话框,这样activity就会在其后可见)。

2.进程持有一个Service,这个Service和一个可见的(或者前台的)Activity绑定。

可见的进程也被认为是很重要的,一般不会被销毁,除非是为了保证所有前台进程的运行而不得不杀死可见进程的时候。

服务进程 (Service process)

如果一个进程中运行着一个service,这个service是通过 startService() 开启的,并且不属于上面两种较高优先级的情况,这个进程就是一个服务进程。

尽管服务进程没有和用户可以看到的东西绑定,但是它们一般在做的事情是用户关心的,比如后台播放音乐,后台下载数据等。所以系统会尽量维持它们的运行,除非系统内存不足以维持前台进程和可见进程的运行需要。

后台进程 (Background process)

如果进程不属于上面三种情况,但是进程持有一个用户不可见的activity(activity的onStop()被调用,但是onDestroy()没有调用的状态),就认为进程是一个后台进程。

后台进程不直接影响用户体验,系统会为了前台进程、可见进程、服务进程而任意杀死后台进程。

通常会有很多个后台进程存在,它们会被保存在一个LRU (least recently used)列表中,这样就可以确保用户最近使用的activity最后被销毁,即最先销毁时间最远的activity。

空进程 (Empty process)

如果一个进程不包含任何活跃的应用组件,则认为是空进程。

例如:一个进程当中已经没有数据在运行了,但是内存当中还为这个应用驻留了一个进程空间。
保存这种进程的唯一理由是为了缓存的需要,为了加快下次要启动这个进程中的组件时的启动时间。系统为了平衡进程缓存和底层内核缓存的资源,经常会杀死空进程。

注意事项:
当我们谈论进程优先级的时候是以 activity、service 这样的组件来说的,但请记住这些优先级是在进程的级别上,不是组件级别上。只要一个组件(比如一个前台服务)就会将整个进程变为前台进程。绝大多数应用是单进程的,如果你有生命周期差异很大的不同部分或者某个部分非常重量型,那么强烈建议你把它们分为不同的进程,让重量级进程尽早被回收。

Service中新开线程和直接新开线程的区别

若直接在Activity中新开一条线程来做耗时操作,当该Activity退出到桌面或其他情况时将成为一个后台进程
若在Service中新启动线程,则此时Android会依据进程中当前活跃组件重要程度,将其判断为服务进程,优先级比(1)高。

因为服务进程的优先级比后台进程的优先级高,所以对于一个需要启动一个长时间操作的activity来说,开启一个service比创建一个工作线程的方法更好,尤其是对于操作将很可能超出activity的持续时间时。

比如要上传一个图片文件,应该开启一个service来进行上传工作,这样在用户离开activity时工作仍在进行。使用service将会保证操作至少有服务进程的优先级。

尽可能保证Service不死常用技巧总结

1、在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时实用于广播:

<service       android:name="com.dbjtech.acbxt.waiqin.UploadService"       android:enabled="true" >       <intent-filter android:priority="1000" >           <action android:name="com.dbjtech.myservice" />       </intent-filter>  </service> 

2、在onStartCommand()里面调用 startForeground()把Service提升为前台进程级别,然后再onDestroy()里面要记得调用stopForeground ()方法。

3、onStartCommand()的返回值
onStartCommand(),返回的是一个int整形。
这个整形可以有以下四个取值:
1)START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
2)START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
3)START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
4)START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

4、在onDestroy()方法里发广播重启service。
service + broadcast 方式,就是当serviceonDestroy()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service。(第三方应用或是在setting里-应用-强制停止时,APP进程就直接被干掉了,onDestroy()都进不来,所以无法保证会执行)

5、监听系统广播判断Service状态。
通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活。

6、Application加上Persistent属性。
加上以上属性相当于将该进程设置为常驻内存进程

比如系统phone中配置了android:persistent=”true”属性,并且Phone.apk是安装在/system/app/目录下的,所以在开机时会自动启动PhoneApp类。

切记,这个不可滥用,一般只适用于放在/system/app下的app,系统中用这个的service,app一多,整个系统可能就会崩溃。

参考:
1.生还是死?Android 进程优先级详解
2.Android开发之如何保证Service不被杀掉(broadcast+system/app)
3.Android基础总结——进程优先级及提高优先级的方法(Service尽量不死之法)