Android 常驻进程保活自启动方案总结

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值
Android 常驻进程保活自启动方案总结_第1张图片
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700 解释如下:
max是指系统最大值为1001,优先级最低,当前值cur=700

Android 常驻进程保活自启动方案总结_第2张图片
此时cur=-10000 ,如上所说值越小,优先级越大

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

你可能感兴趣的:(Android,细节技巧总结,android,进程守护,进程自启动,前台进程设置)