Android通过JobScheduler与设置前台服务实现进程保活

在Android系统中,后台服务很容易由于各种原因被系统(手机厂商)杀掉,这就需要开发者对自己的应用进程进行保活,以满足一些功能需求(例如消息推送,音乐播放)。常见的保活方案很多,详情可以看Android进程保活招式大全,本文就新版本比较常用的方案设置前台服务与JobScheduler展开讨论。

一、设置前台服务

1.1如何设置前台服务

设置前台服务在代码中的设置很简单即在service中调用:

startForeground(1,getNotification());

第一个参数是通知id,第二个参数是Notification实例。这个通知也就是这个前台服务要绑定的通知。没错,前台服务必须要绑定一个通知,不然你以为google能给你无缘无故提升服务优先级吗?那么有没有方法去除这个通知栏,降低用户感知度呢?下一节介绍。
好了,设置前台服务是不是很简单呢?别急,我在调用的时候突然发现跟startForeground方法很像的一个方法startForegroundService(Intent service),而且这还是个android O中的新方法,于是google了一下官网,结果发现:


android o关于后台服务限制.png

但是我调试了一下,在我的小米mix2(android8.0.0)和nexus6p(android8.0.0)直接使用startService启动服务都没有问题!当然使用startForegroundService启动服务,然后再使用startForeground设置前台进程也没有问题。难道是官网骗我???可能在比较新的android O中会有这个限制吧。。。

1.2如何去除前台服务的通知栏提醒

方案也是google找的,这里就复述一下,思路就是利用2个同进程的service,利用相同的notificationID,2个service分别startForeground,然后只在1个service里stopForeground,这样即可去掉通知栏的显示。
代码实现:
在你想保活的service的onCreate()方法中,绑定一个用来消除通知的服务:

if (mConnection == null) {
       mConnection = new InnerServiceConnection();
}
this.bindService(new Intent(this, InnerService.class), mConnection, Service.BIND_AUTO_CREATE);

InnerService中的代码:

public class InnerService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new LocalBinder();
    }

    public class LocalBinder extends Binder {
        public InnerService getService() {
            return InnerService.this;
        }
    }

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

InnerServiceConnection的实现:

private class InnerServiceConnection implements ServiceConnection {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "MyService: onServiceDisconnected");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            Log.d(TAG, "MyService: onServiceConnected");
            // 的,会在通知栏显示service正在运行,这里不要让用户感知,所以这里的实现方式是利用2个同进程的service,利用相同的notificationID,
            // 2个service分别startForeground,然后只在1个service里stopForeground,这样即可去掉通知栏的显示
            Service innerService = ((InnerService.LocalBinder) binder)
                    .getService();
            MainService.this.startForeground(1, getNotification());
            innerService.startForeground(1, getNotification());
            innerService.stopForeground(true);
            MainService.this.unbindService(mConnection);
            mConnection = null;
        }
    }

1.3设置前台服务总结

设置了前台服务后,服务一般就不会被系统自动清除了,但在miui这类专治流氓软件的系统中,用户手动清除后台,你的进程仍然会被杀掉(android原生系统中,亲测不会被杀掉)。那该怎么办呢?一般的方案是用一些手段重启服务。接下来介绍JobScheduler

二、JobScheduler

JobScheduler是android 5.0提供的一个API,可以指定一段时间循环执行特定的任务,这些任务都会被系统统一调度执行。因为以前大家的应用都是监听各种广播自启动,google终于忍不了了。

2.1JobScheduler的使用

先上调用代码:
        //获取JobScheduler 他是一种系统服务
        JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobScheduler.cancelAll();
        JobInfo.Builder builder = new JobInfo.Builder(1024, new ComponentName(getPackageName(), JobProtectService.class.getName()));

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //android N之后时间必须在15分钟以上
//            builder.setMinimumLatency(10 * 1000);
            builder.setPeriodic(15 * 60 * 1000);
        }else{
            builder.setPeriodic(60 * 1000);
        }
        builder.setPersisted(true);
        builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
        int schedule = jobScheduler.schedule(builder.build());
        if (schedule <= 0) {
            Log.w(TAG, "schedule error!");
        }

这里JobInfo中包含了要执行的信息,JobInfo.Builder是他的构造器,其中:

JobInfo.Builder builder = new JobInfo.Builder(1024, new ComponentName(getPackageName(), JobProtectService.class.getName()));

是他的构造方法,指定了要跳转的JobService的信息

builder.setPeriodic(long intervalMillis)

表示间隔一定时间执行该任务,在version>=android N的系统版本中,这个值只能是15分钟以上

builder.setMinimumLatency(long minLatencyMillis);

表示延迟一定时间执行任务,改任务只会调用一次,这个值在android N中没有限制,所以如果你想突破setPeriodic中15分钟的限制,你可以使用setMinimumLatency方法,并在执行任务结束的时候再调用这个方法,等会介绍一下。

builder.setPersisted(true);

是否开机启动?这个方法需要权限


在国产rom中应用没开自启动你就别想了

 builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);

表示网络状态的限制

//不管是否有网络这个任务都会被执行
JobInfo.NETWORK_TYPE_NONE
//任意一种网络任务可以执行
JobInfo.NETWORK_TYPE_ANY
//它表示设备在WIFI连接时任务才会被执行
JobInfo.NETWORK_TYPE_UNMETERED
int schedule = jobScheduler.schedule(builder.build());

表示执行该任务,返回值>0表示执行成功

JobService代码:
public class JobProtectService extends JobService {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent,flags,startId);
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        //TODO 写上你的任务逻辑代码
        jobFinished(params, false);
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
}

2.2JobScheduler总结

JobScheduler用来检测你自己的服务是否被杀掉,如果被杀掉了,你重启自己的服务,经过测试,在miui等国产rom中也能够重启服务,前提是你的应用有自启动权限!

你可能感兴趣的:(Android通过JobScheduler与设置前台服务实现进程保活)