Android常驻进程就是进程一直存在,即使被系统外者其他软件人为杀死也能够自启,这种需求一般就是用来常驻接受推送消息时,如何保证进程不被杀死,实时收到推送的消息,与后台保持着链接。那如何保持进程常驻呢,总结了如下方案:

##提高进程优先级以及等级
Android系统进程管理对进程分等级,当内存不足时按照等级排序从最低等级最先杀死用来回收内存,进程等级排名如下
1.前台进程( FOREGROUND_APP)
前台进程是目前正在屏幕上显示的进程和一些系统进程,也就是和用户正在交互的进程
2.可视进程(VISIBLE_APP )
可见进程指部分程序界面能够被用户看见,却不在前台与用户交互的进程。
3.次要服务进程(SECONDARY_SERVER )
服务进程是通过 startService() 方法启动的进程,但不属于前台进程和可见进程。例如,在后台播放音乐或 者在后台下载就是服务进程
4.后台进程 (HIDDEN_APP)
后台进程指的是目前对用户不可见的进程。当点击Home键让qq界面消失的时候,这个时候它就转换成了后台进 程。
5.内容供应节点(CONTENT_PROVIDER)
6.空进程(EMPTY_APP)
空进程指的是在这些进程内部,没有任何东西在运行。保留这种进程的的唯一目的是用作缓存,以缩短该应用下次在其中运行组件所需的启动时间。
所以我们最基本的措施是先竟可能的提高等级,措施如下:
1、配置Android:priority:对于Service被系统回收,一般做法是通过提高优先级可以解决,在AndroidManifest.xml文件中对于intent-filter可以通过Android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低。
2、生命周期中执行不可中断任务,阻塞主线程:如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
3、bindService:如果客户端已经连接到service
(bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
4、startForeground(int, Notification):如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
Android7.1以下系统bug而生的黑科技-设置为前台进程却不显示Notification
具体做法就是先后启动两个service,并配置startForeground(int, Notification)相同的id,后一个service然后又stopself退出,消去了notification,从而使得第一个service成为前台进程等级。详细原理解释:http://blog.csdn.net/pw4work/article/details/52877980?utm_source=itdadao&utm_medium=referral

5、增强进程可见性:如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。例如见过一个比较狠的方式:启动显示出一个透明的小窗口Activity来来提高可见性

##进程自启动方案
1、Service中onStartCommand方法return START_STICKY;
通过return START_STICKY;系统会在内容不足杀死进程之后,会重新启动该进程。这种方式比较靠谱,作为补充手段

2、监听系统广播来自启动
通过监听系统广播如解锁屏、网络变化、安装卸载应用等这些广播时,判断进程状态,如果进程不存在,就重新启动。

                                                                                                                  
这种方式存在局限于某些机型收不到广播,或者广播收到有要求,但大部分机型还是比较有用,作为主力之一。

3、双进程互相守护
同时开启了两个Service,分别是A和B,互相守护, 如果A守护B,当B挂掉,A就立刻把B启动起来,所以A和B互相守护,无论谁被杀掉,对方就把它拉起来。具体通过bindService方式来互相绑定对方,分别在不同的进程中避免同时被杀死。
定义两个Service,分别是LocalService和RemoteService,其中的RemoteService我们通过属性配置android:process=”:remote”代码如下:

 public class LocalService extends Service {    private MyBinder mBinder;    private PendingIntent mPintent;    private MyServiceConnection mServiceConnection;    @Override    public void onCreate() {        super.onCreate();        if (mBinder == null) {            mBinder = new MyBinder();        }        mServiceConnection = new MyServiceConnection();    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        bindService(new Intent(this, RemoteService.class), myServiceConnection, Context.BIND_IMPORTANT);        Notification notification = new Notification(R.drawable.ic_launcher, "", System.currentTimeMillis());        mPintent = PendingIntent.getService(this, 0, intent, 0);        notification.setLatestEventInfo(this, "", "自启", pintent);               startForeground(startId, notification);        return START_STICKY;    }    class MyServiceConnection implements ServiceConnection {        @Override        public void onServiceConnected(ComponentName arg0, IBinder arg1) {                }        @Override        public void onServiceDisconnected(ComponentName arg0) {            // 连接出现了异常断开了,被杀掉了            Toast.makeText(LocalService.this, "远程服务Remote被干掉", Toast.LENGTH_LONG).show();            startService(new Intent(LocalService.this, RemoteService.class));            bindService(new Intent(LocalService.this, RemoteService.class),                    mServiceConnection, Context.BIND_IMPORTANT);        }    }    class MyBinder extends Connection.Stub {        @Override        public String getProName() throws RemoteException {            return "";        }    }    @Override    public IBinder onBind(Intent arg0) {        return mBinder;    }}   
public class RemoteService extends Service {    private  MyBinder mBinder;    private PendingIntent mPintent;    private MyServiceConnection mServiceConnection;     @Override    public void onCreate() {        super.onCreate();        if (myBinder == null) {            mBinder = new MyBinder();        }        mServiceConnection = new MyServiceConnection();    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        this.bindService(new Intent(this,LocalService.class), mServiceConnection, Context.BIND_IMPORTANT);        Notification notification = new Notification(R.drawable.ic_launcher,                "",                System.currentTimeMillis());        mPintent=PendingIntent.getService(this, 0, intent, 0);        notification.setLatestEventInfo(this, "",                "防止被杀掉!", pintent);        startForeground(startId, notification);        return START_STICKY;    }    class MyServiceConnection implements ServiceConnection {        @Override        public void onServiceConnected(ComponentName arg0, IBinder arg1) {                    }        @Override        public void onServiceDisconnected(ComponentName arg0) {            Toast.makeText(RemoteCastielService.this, "本地服务Local被干掉", Toast.LENGTH_LONG).show();            startService(new Intent(RemoteService.this,LocalService.class));           bindService(new Intent(RemoteService.this,LocalService.class), mServiceConnection, Context.BIND_IMPORTANT);        }    }    class MyBinder extends Connection.Stub {        @Override        public String getProName() throws RemoteException {            return "";        }    }    @Override    public IBinder onBind(Intent arg0) {        return mBinder;    }}
扩展思路: 甚至可以是更多的进程之间串连方式,连成一条线互相监听,A-B-C-D-E-A 这种环形监听方式。

4、特定时间特定场景下检查
直接通过设定定时任务来检查进程是否存在,可以通过两种方式来:
1)监听系统时钟广播或AlarmManager周期性来检查进程状态。
2)5.0以后的Android系统,我们就可以使用JobScheduler,JobScheduler来可以调度特殊场景下启动JobService来执行onStartJob,如设定wifi连接时候啊,JobService是Android5.0以后新增的一个服务,即可以通过JobScheduler来执行一些满足特定条件但不紧急的后台任务,那我们就可以设定这个任务就是定时检查进程是否存在,后续详细讲解这种方式,详细参考另一边文章:http://blog.csdn.net/u010019468/article/details/72958859。

5、全家桶互拉方式
这种方案常见于百度、360等全家桶,这种互相唤醒的方式,可以参考,但不要过分哦。

6、后台播放无声音乐
这种方案应用比较多,且比较有效,且高版本息屏下也可以保活,循环播放会比较耗时,一般会间隔几分钟,但是若息屏下间隔事件要控制到小间隔,过长的话,会被回收,实际使用中可以采取lenght+xxx
这种保活的根本原因,就是把进程的优先级提高到很高了,可以查看oom_adj变化,说明下,该值越小说明优先级越大。
测试效果如下:把应用都退到后台,无播放的情况如下图1所示oom_adj值

oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700 解释如下:
max是指系统最大值为1001,优先级最低,当前值cur=700


此时cur=-10000 ,如上所说值越小,优先级越大

总结:上述方式没有一个是万能的报活方式,都会存在不适配,这种情况下就不要单独依赖某种方式,而是综合使用多种方式,甚至可以全部使用,来做个万全之策,不论那种方式命中,都检查进程状态,而不要导致混乱。

更多相关文章

  1. android 车机电话的通讯录联系人搜索实现解析 ------- 填坑日记
  2. 杂谈:后台进程对Android性能的影响
  3. Android的BUG(四) - Android(安卓)app的卡死问题
  4. Android如何判断是否是平板
  5. 在Android中通过jni方式使用编译好的FFmpeg库-Android中使用FFmp
  6. Linux Kernel and Android(安卓)休眠与唤醒(中文版)
  7. 无标题文浅入浅出 Android(安卓)安全 (三) Android(安卓)本地用户
  8. Android(安卓)进阶之了解源码——Activity启动
  9. 查看Android(安卓)API文档的正确方式

随机推荐

  1. 【DB笔试面试728】在Oracle中,如何修改RAC
  2. oracle 从执行计划的预估行数看执行计划
  3. Oracle分批提交DML
  4. 在Oracle中,如何定时删除归档日志文件?
  5. Citrix MCS桌面模板更新
  6. Oracle角色权限之Default Role
  7. 【DB笔试面试759】在Oracle中,如果主库丢
  8. Oracle绑定变量分级(Bind Graduation)
  9. 【DB笔试面试719】在Oracle中,什么是OCR、
  10. Oracle结果集缓存(Result Cache)--服务器、