您的位置:首页 > 移动开发 > Android开发

Android进阶之进程优先级及提高优先级的方法(进程保活)

2017-01-18 18:28 411 查看

1 生命周期

  service:是一个后台服务,专门用来处理常驻后台的工作的组件。系统会尽可能长的延续一个应用程序进程,但在内存过低的时候,仍然会不可避免需要移除旧的进程。为了决定哪些进程留下,哪些进程被杀死,系统根据在进程中在运行的组件及组件的状态,为每一个进程分配了一个优先级等级。优先级最低的进程首先被杀死。这个进程重要性的层次结构主要有五个等级。

  Android会尽可能高的估量一个进程的级别。比如,一个进程拥有一个可见状态的activity和一个service,这个进程会被认为是可见进程,而不是服务进程。

  一个进程的级别可能会由于其它进程依赖于它而升高。一个为其它进程提供服务的进程级别永远高于使用它服务的进程。比如说,如果A进程中的内容提供者为进程B中的客户端提供服务,或进程A中的服务为进程B中的组件所绑定,则A进程高于或者等于进程B的等级。

2 进程的五个常用等级

  进程的重要性优先级:(越往后的就越容易被系统杀死)

2.1 前台进程:Foreground process

  杀死前台进程需要用户交互,因为前台进程的优先级是最高的。

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

  (2)进程持有一个Service,这个Service处于这几种状态:①Service与用户正在交互的Activity绑定。Service调用了startForeground(),在前台运行。Service执行在用户正在交互的Activity的生命周期回调函数中(onCreate(), onStart(), onDestroy())。

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

2.2 可见进程:Visible process

  如果一个进程不含有任何前台的组件,但仍可被用户在屏幕上所见。可见的进程也是很重要的,一般不会被销毁,除非是为了保证所有前台进程的运行而不得不杀死可见进程的时候。当满足如下任一条件时,进程被认为是可见的:

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

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

2.3 服务进程:Service process

  一个进程中运行着一个service,这个service是通过startService()开启的

  (1)比如后台播放音乐,后台下载数据等。

2.4 后台进程:Background process

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

  (1)进程持有一个用户不可见的Activity(activity的onStop()被调用,当此Activity退出到桌面),就认为进程是一个后台进程。后台进程不直接影响用户体验,系统会为了优先级高的进程而任意杀死后台进程。

2.5 空进程:Empty process

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

  (1)一个进程不包含任何活跃的应用组件,则认为是空进程(android设计的,为了第二次启动更快,采取的一个权衡)

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

  因为服务进程的优先级比后台进程的优先级高,所以对于一个需要启动一个长时间操作的activity来说,尤其是对于操作将超出activity的持续时间时,开启一个service比创建一个工作线程的方法更好。比如:要上传一个图片文件,应该开启一个service来进行上传工作,这样在用户离开activity时工作仍在进行。使用service将会保证操作至少有服务进程的优先级。

  (1)若直接在Activity中新开一条线程来做耗时操作,当该Activity退出到桌面或其他情况时将成为一个后台进程

  (2)若在Service中新启动线程,则此时Android会依据进程中当前活跃组件重要程度,将其判断为服务进程,优先级比(1)高

4 保证Service不死常用技巧总结(要根据自己的需要来使用)

4.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>


4.2 startForeground()方法

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

4.3 onStartCommand方法,返回START_STICKY

  在onStartCommand方法中手动返回START_STICKY,当service因内存不足被kill,当内存又存在的时候,service又被重新创建,但是不能保证任何情况下都被重建,比如:进程被干掉了。

public int onStartCommand(Intent intent, int flags, int startId) {
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
}


  补充说明: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.4 在onDestroy方法里发广播重启service

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

<receiver android:name="com.dbjtech.acbxt.waiqin.BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.dbjtech.waiqin.destroy" />//这个就是自定义的action
</intent-filter>
</receiver>


//在onDestroy时
@Override
public void onDestroy() {
stopForeground(true);
Intent intent = new Intent("com.dbjtech.waiqin.destroy");
sendBroadcast(intent);
super.onDestroy();
}


//在BootReceiver里
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.dbjtech.waiqin.destroy")) {
//在这里写重新启动service的相关操作
startUploadService(context);
}
}
}


4.5 监听(系统)广播判断Service状态

  通过监听系统、QQ,微信,系统应用,友盟推送等的一些广播,比如:手机重启、界面唤醒、应用状态改变等监听并捕获到,然后判断我们的Service是否还存活,并唤醒自己的App。这是大厂常用方法,例如:阿里收购友盟后,通过友盟的广播唤醒阿里的App,然后把自己启动了。

<receiver android:name="com.dbjtech.acbxt.waiqin.BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.intent.action.PACKAGE_RESTARTED" />
<action android:name="com.dbjtech.waiqin.destroy" />
</intent-filter>
</receiver>


//BroadcastReceiver中
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
System.out.println("手机开机了....");
startUploadService(context);//开启服务
}
if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
startUploadService(context);
}
}


4.6 Application加上Persistent属性

  看Android的文档知道,当进程长期不活动,或系统需要资源时,会自动清理门户,杀死一些Service,和不可见的Activity等所在的进程。但是如果某个进程不想被杀死(如数据缓存进程,或状态监控进程,或远程服务进程),应该怎么做,才能使进程不被杀死。

//加上以上属性相当于将该进程设置为常驻内存进程。
add android:persistent=”true” into the section in your AndroidManifest.xml


  切记,这个不可滥用,一般只适用于放在/system/app下的app,系统中用这个的service,app一多,整个系统可能就会崩溃。比如系统phone中配置了android:persistent=”true”属性,并且Phone.apk是安装在/system/app/目录下的,所以在开机时会自动启动PhoneApp类。

4.7 类似监听锁屏方法

4.7.1 需求

QQ采取在锁屏的时候启动一个1个像素的Activity,当用户解锁以后将这个Activity结束掉(顺便同时把自己的核心服务再开启一次)。
故事:小米撕逼。
背景:当手机锁屏的时候什么都干死了,为了省电。
锁屏界面在上面盖住了。
监听锁屏广播,锁了---启动这个Activity。
监听锁屏的,开启---结束掉这个Activity。
要监听锁屏的广播---动态注册。
ScreenListener.begin(new xxxListener
onScreenOff()
);

被系统无法杀死的进程。


4.7.2 参考源码

双进程守护+锁屏



4.8 双进程守护+JobScheduler调度

4.8.1 概念

  双进程守护—可以防止单个进程杀死,同时可以防止第三方的360清理掉。

一个进程被杀死,另外一个进程又被他启动。相互监听启动。A<—>B,杀进程是一个一个杀的。本质是和杀进程时间赛跑。

  JobScheduler源码分析:JobScheduler来执行一些需要满足特定条件但不紧急的后台任务,把任务加到系统调度队列中,当到达任务窗口期的时候就会执行,我们可以在这个任务里面启动我们的进程。这样可以做到将近杀不死的进程。

4.8.2 参考源码



4.8.3 结果截图

双进程守护+锁屏



4.9 其他

(1)App运营商与手机厂商合作,列入白名单。

(2)利用账号同步机制唤醒我们的进程。

(3)NDK来解决,Native进程来实现双进程守护。

5 参考链接

Android基础总结——进程优先级及提高优先级的方法(Service尽量不死之法)

【腾讯Bugly干货分享】Android 进程保活招式大全
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 内存 结构