进程划分:(从高到底)
1、前台进程
①某进程持有一个正在与用户进行交互的Activity并该Activity正在处于resume状态
②某进程持有一个Service,并且该Service与用户正在交互的Activity绑定
③某进程持有一个Service,且该Service调用startForeground()方法使之位于前台运行。
④某进程持有一个Service,且该Service正在执行它的某个生命周期回调方法,比如onCreate()、 onStart()或onDestroy()。
⑤某个进程持有一个BroadcastReceiver,并且该BroadcastReceiver正在执行其onReceive()方法。
2、可见进程
①拥有不在前台但仍对用户可见的Activity(已调用onPause)
②拥有绑定到可见Activity的Service
3、服务进程 某个进程中运行着一个Service且该Service是通过startService()启动的,与用户看见的界面没有直接关联。
4、后台进程 在用户按了"back"或者"home"后,程序本身看不到了,但是其实还在运行的程序,比如Activity调用了onPause方法
5、空进程 某个进程不包含任何活跃的组件时该进程就会被置为空进程,完全没用,杀了它只有好处没坏处,第一个干它!
进程回收机制
app在退出后台时系统并不会真正的kill这个进程,而是将其缓存起来,打开的应用越多,后台缓存的进程也就越多,在系统内存不足的情况下,系统会依照自身进程回收机制来判断kill哪些进程,以腾出内存给需要的app
进程回收机制就是根据 oom_adj 这个优先级来决定是否进行回收 ①进程的oom_adj 越大,表示优先级越低,越容易被回收。反之。 ②普通app进程oom_adj >=0,系统进程的app的oom_adj 才可能<0
进程保活方案:
黑色保活:
①开机,网络切换、拍照、拍视频的时候,利用系统产生的广播唤醒app【但是,最新的Android N已经取消了开机,网络切换、拍照、拍视频三种广播,而且开机广播的话,一些定制ROM的厂商早已将其去掉】
②接入第三方SDK也会唤醒相应的app进程,比如微信sdk会唤醒微信,支付宝sdk会唤醒支付宝
③假如你手机里装了支付宝、淘宝、天猫、UC等阿里系的app,那么你打开任意一个阿里系的app后,有可能就顺便把其他阿里系的app给唤醒了。
白色保活: 调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,哪怕退到后台,用户也是知道有这样一个app在运行着,比如QQ音乐等
灰色保活: 应用范围最广范。是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程一样。这样做带来的好处就是,用户无法察觉到你运行着一个前台进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢,大致的实现思路和代码如下:
思路一:API < 18,启动前台Service时直接传入new Notification()
; 思路二:API >= 18,同时启动两个id相同的前台Service,然后再将后启动的Service做stop处理;
public class GrayService extends Service {
private final static int GRAY_SERVICE_ID = 1001;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT < 18) {
startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 ,此方法能有效隐藏Notification上的图标
} else {
Intent innerIntent = new Intent(this, GrayInnerService.class);
startService(innerIntent);
startForeground(GRAY_SERVICE_ID, new Notification());
}
return super.onStartCommand(intent, flags, startId);
}
...
...
/**
* 给 API >= 18 的平台上用的灰色保活手段
*/
public static class GrayInnerService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(GRAY_SERVICE_ID, new Notification());
stopForeground(true);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
}
}
使用灰色保活并不代表着你的Service就永生不死了,只能说是提高了进程的优先级。如果你的app进程占用了大量的内存,按照回收进程的策略,同样会干掉你的app。 app退到后台时,其所有的进程优先级都会降低。但是UI进程是降低最为明显的,因为它占用的内存资源最多,系统内存不足的时候肯定优先杀这些占用内存高的进程来腾出资源。所以,为了尽量避免后台UI进程被杀,需要尽可能的释放一些不用的资源,尤其是图片、音视频之类的。
其他方案:
JobSheduler: JobSheduler是作为进程死后复活的一种手段,native进程方式最大缺点是费电, Native 进程费电的原因是感知主进程是否存活有两种实现方式,在 Native 进程中通过死循环或定时器,轮训判断主进程是否存活,当主进程不存活时进行拉活。其次5.0以上系统不支持。 但是JobSheduler可以替代在Android5.0以上native进程方式,这种方式即使用户强制关闭,也能被拉起来,
粘性服务&与系统服务捆绑: 这个是系统自带的,onStartCommand方法必须具有一个整形的返回值,这个整形的返回值用来告诉系统在服务启动完毕后,如果被Kill,系统将如何操作,这种方案虽然可以,但是在某些情况or某些定制ROM上可能失效,我认为可以多做一种保守方案
-
START_STICKY 如果系统在onStartCommand返回后被销毁,系统将会重新创建服务并依次调用onCreate和onStartCommand(注意:根据测试Android2.3.3以下版本只会调用onCreate根本不会调用onStartCommand,Android4.0可以办到),这种相当于服务又重新启动恢复到之前的状态了)。
-
START_NOT_STICKY 如果系统在onStartCommand返回后被销毁,如果返回该值,则在执行完onStartCommand方法后如果Service被杀掉系统将不会重启该服务。
-
START_REDELIVER_INTENT START_STICKY的兼容版本,不同的是其不保证服务被杀后一定能重启。
网友评论