1.概论
进程保活主要是抓住两个关键点,一个是进程的优先级,优先级越高存活几率越大;二是弄清楚哪些场景会导致进程会kill。基于这两个原因一般是会采取下面的策略对各种场景进行优化:提高进程的优先级和在进程被kill之后能够唤醒
2.场景优化
2.1提高进程的优先级
Android一般的进程优先级划分【具体细节划分可以参照https://developer.android.com/guide/components/processes-and-threads#Processes】:
前台进程 (Foreground process): 前台进程是目前正在屏幕上显示的进程和一些系统进程【比如正在进行的QQ聊天】
可见进程 (Visible process): 能够被用户看见,却不在前台与用户交互的进程【比如弹出的对话框】
服务进程 (Service process):服务进程是通过startService() 方法启动的进程,但不属于前台进程和可见进程【比如音乐播放】
后台进程 (Background process):后台进程指的是目前对用户不可见的进程。【如如按下Home键QQ退到后台】
空进程 (Empty process):空进程指的是在这些进程内部,没有任何东西在运行,其主要作用是用来做缓存,缩短下次启动时间。
以上进程回收顺序依次为:空进程,后台进程,服务进程,可见进程,前台进程。
以上划分是一种粗略的划分,进程其实有一种具体的数值,称作oom_adj,
数值越大优先级越低:

红色部分是容易被回收的进程,属于android进程
绿色部分是较难被回收的进程,属于android进程
其他部分则不是android进程,也不会被系统回收,一般是ROM自带的app和服务才能拥有
oom_adj 存储在proc/PID/oom_adj文件中,其中PID是进程的id,直接 adb shell进入手机根目录查看这个文件即可。
如通过DDMS可以查看不同应用的进程pid。

在启动的时候startService,设置该service的android:process=":remote"依次在应用处于前台和按下home键后我们可以看到oom_adj 的值分别不一样

具有相同omm_adj的进程,则杀死占用内存较多的,因此,如果我们的APP进入后台,就尽量释放不必要的资源,以降低自己被杀的风险。
进程被kill的场景:
1. 点击home键使app长时间停留在后台,内存不足被kill。
处理这种情况前提是你的app至少运行了一个service,然后通过Service.startForeground() 设置为前台服务,可以将oom_adj的数值降低,大大提高存活率。可以通过命令adb shell dumpsys activity services packageName 来查看是否采用此方式。
2.在大多数国产手机下,进入锁屏状态一段时间,省电机制会kill后台进程
这时候我们可以监听锁屏和解锁广播来做一些处理。一般是在接到锁屏广播的时候启动一个1像素透明的Activity,接收解锁广播后销毁该Activity。主要的action为:android.intent.action.SCREEN_OFF
android.intent.action.SCREEN_ON
这两个action 静态注册不会生效,因此我们需要采用动态注册方式注册。
3. 用户手动释放内存:包括手机自带清理工具,和第三方app(360,猎豹清理大师等),这种场景下理论上可以杀掉任何app。
一般是在在app的设置界面加一个选项,提示用户自己去勾选自启动:

这个需要注意不同手机的页面不同,比如本机是:
cmp=com.android.settings.apprestrict.AppRestrictionsActivity因此要多机型测试。【网上可以搜索到一些常用机型的activity】
3进程唤醒
[if !supportLists]1. [endif]service的后台进程被kill,可以通过service自有api来重启Service:

Service 主要有以下几个返回值:
START_STICKY
当Service因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试重新创建此Service.一旦创建成功后将回调onStartCommand方法,但其中的Intent将是null,除非有挂起的Intent,如pendingintent,这个状态下比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。
START_NOT_STICKY
当Service因内存不足而被系统kill后,即使系统内存再次空闲时,系统也不会尝试重新创建此Service。除非程序中再次调用startService启动此Service,这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
START_REDELIVER_INTENT
当Service因内存不足而被系统kill后,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand(),任何挂起 Intent均依次传递。与START_STICKY不同的是,其中的传递的Intent将是非空,是最后一次调用startService中的intent。这个值适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
1. 通过AlarmManager和系统广播来在一定条件下唤醒逝去的进程。
2. Android5.0之后Android提供了JobService和JobScheduler这两的类。我们可以通过这个JobScheduler来进行保活。
3. 进程守护AB两个进程,A进程里面轮询检查B进程是否存活,没存活的话将其拉起,同样B进程里面轮询检查A进程是否存活,没存活的话也将其拉起。同样可以采用C层fork,也可以直接Java创建一个新的进程。
4. 相互唤醒的意思就是,假如你手机里装了QQ、微信、腾讯视频等腾讯系的app,那么你打开任意一个腾讯系的app后,有可能就顺便把其他腾讯系的app给唤醒了。
5. 与系统Service捆绑,例如NotificationListenerService

NotificationListenerService是个特殊的系统Service,需要非常特别的权限,需要你手动在“设置-提示音和通知-通知使用权限”中打开。
网友评论