美文网首页AndroidAndroid
Android通过JobScheduler与设置前台服务实现进程

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

作者: zvl | 来源:发表于2018-04-28 11:49 被阅读377次

    在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);
    

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

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    

    在国产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与设置前台服务实现进程

      本文链接:https://www.haomeiwen.com/subject/xiiwlftx.html