JobScheduler API的使用详细

首先需要注意,本人使用的测试手机是Android7.0,荣耀华为6x,还有就是注意红色文字,基本是结论或者重点

1.简介

JobScheduler API是在Android5.0开始有的,使用场景:在稍后的某个时间点或者当满足某个特定的条件(连接电源,网络状态变化、手机是否空闲)时需要执行一个任务。

2.API函数

开发者主要通过三个类JobService和JobScheduler、JobInfo来使用JobSchedule API

而且你要知道一件事,一旦通过命令开启了任务,只要符合条件就会执行任务,除非应用程序死亡,所以比如设置周期运行任务的,会不断的启动任务

JobScheduler实现了任务的调度,相关函数如下

/*返回值:1表示执行成功,0代表失败*/
public abstract int schedule(JobInfo job);
/**通过指定的jobId取消Job任务*/
public abstract void cancel(int jobId);

/**取消所有的Job任务*/
public abstract void cancelAll();

/**获取所有的未执行的Job任务*/
public abstract @NonNull List<JobInfo> getAllPendingJobs();

/**获取指定的Job未执行的任务*/
public abstract @Nullable JobInfo getPendingJob(int jobId);

JobService是一个抽象类,是Service的继承类,我们需要实现两个个函数,来完成任务执行的开始和停止

/*开启任务*/
public abstract boolean onStartJob(JobParameters params);
/*停止任务方法*/
public abstract boolean onStopJob(JobParameters params);

JobInfo是为了规定任务启动的规则,通过JobScheduler的建造者模式来设置规则

// jobId每个Job任务的id
int jobId = 1;
// 指定你需要执行的JobService
ComponentName name = new ComponentName(getPackageName(), MyJobService.class.getName()));
JobInfo.Builder builder = new JobInfo.Bulider(jobId, name);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE); //设置需要的网络条件,默认NETWORK_TYPE_NONE
builder.setPeriodic(3000);//设置间隔时间,不断的触发任务的启动
builder.setMinimumLatency(3000);// 设置任务运行最少延迟时间,与setPeriodic相似,只是间隔时间不确定,不能与setPeriodic一起使用,
builder.setOverrideDeadline(50000);// 设置deadline,若到期还没有达到规定的条件则会开始执行  
builder.setRequiresCharging(true);// 设置是否充电的条件,默认false
builder.setRequiresDeviceIdle(false);// 设置手机是否空闲的条件,默认false
builder.setPersisted(true);//设备重启之后你的任务是否还要继续执行
JobInfo info = builder.build();

3.各种使用

(1)基础代码

首先我贴出一个最基本JobSheduler API的使用代码,后面的测试代码都是通过这个段代码稍微改动而来的,大家可以边看博客,自己试一试代码的效果

MyJobService就是显示一个Toast,之所以最后是通过Handler实现,是因为想要模仿耗时任务,毕竟这是一个后台Service,使用场景很多是耗时任务。

如果要模拟的不是耗时任务,那就去掉这个Handler,然后将onStartJob的返回值设置为false。因为在onStartJob里返回false代表你任务执行完成了,他会开始计时为下一次任务的执行做准备,如果返回true,代表任务还在执行,需要我们自己调用jobFinished(param,true)函数来告诉JobService任务执行完成了

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)//API需要在21及以上
public class MyJobService extends JobService {

    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            Toast.makeText(MyJobService.this, "MyJobService", Toast.LENGTH_SHORT).show();
            JobParameters param = (JobParameters) msg.obj;
            jobFinished(param, true);

            return true;
        }
    });

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

    @Override
    public boolean onStartJob(JobParameters params) {
        Message m = Message.obtain();
        m.obj = params;
        handler.sendMessageDelayed(m, 2000);
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        handler.removeCallbacksAndMessages(null);
        return false;
    }
}

因为是Service还需要在AndroidManifest注册,只是注册时还需要设置一个特殊的权限

        <service
            android:name=".MyJobService"
            android:permission="android.permission.BIND_JOB_SERVICE"></service>

activity就是设置一个按钮,点击触发任务的调度开启

public class MainActivity extends AppCompatActivity {

    Button btn;
    private JobScheduler mJobScheduler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn = (Button) findViewById(R.id.btn);
        mJobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    JobInfo.Builder builder = new JobInfo.Builder( 1,
                            new ComponentName( getPackageName(), MyJobService.class.getName() ) );
                    builder.setMinimumLatency(2000);
                    if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
                        //If something goes wrong
                    }

                }

            }
        });

    }


}

(2)各种使用情况

setMinimumLatency

基础代码里通过setMinimumLatency(2000)设置任务最少执行延缓,虽然是最少延缓,但是在我的测试下,发现这个延缓时间比较随机,有时候能够在两秒后开始执行任务,不过一般的都是7、8秒开始执行任务。在任务执行完成后,他们会初始化延缓时间,开始计时,准备下一次任务的执行。

setPeriodic

在基础代码里,我把setMinimumLatency(2000)代码换成setPeriodic(2000)

这里要注意setMinimumLatency和setPeriodic不能一起设置,会报错,我想是因为他们都有周期设置任务启动的特性有关。

当我运行代码,应用却没有按照两秒周期的时间触发任务,然后我在控制台看到了如下log

 W/JobInfo: Specified interval for 1 is +2s0ms. Clamped to +15m0s0ms
 W/JobInfo: Specified flex for 1 is +2s0ms. Clamped to +5m0s0ms
就是说你 这个间隔必须在15分钟以上,这个规定是在Android7.0开始有的,所以如果需要比较频繁的调用任务,还是需要使用setMinimumLatency来完成
setRequireNetworkType

如果我把setRequireNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)替换setMinimumLatency(2000),运行程序会报错

java.lang.IllegalArgumentException: You're trying to build a job with no constraints, this is not allowed.
我得出结论setRequireNetworkType不算主约束条件,需要依附像setMinimumLatency类似的主约束条件,那好我添加一个setMinimumLatency(2000000),再来运行,之所以把最少延缓的时间设置的这么大,是因为 只要满足设置的条件之一就会启动任务
然后运行程序, 当我们连接WIFI,就会触发任务 ,市面很多通知栏广告就是使用这个类型的网络类型触发的,因为JobInfo规定的网络类型还有几个,我就不试了,大家可以自己试试
    public static final int NETWORK_TYPE_ANY = 1;
    public static final int NETWORK_TYPE_METERED = 4;
    public static final int NETWORK_TYPE_NONE = 0;
    public static final int NETWORK_TYPE_NOT_ROAMING = 3;
    public static final int NETWORK_TYPE_UNMETERED = 2;
setRequiresChargin

setRequiresChargin不是主约束条件, 将setRequiresChargin(true)替换setRequireNetworkType(JobInfo.NETWORK_TYPE_UNMETERED),运行程序,额,没效果,有点尴尬,知道原因的同学,可以教一下我

setRequiresChargin(true)指的是监听充电,如果给的false就不监听,所以默认就是false

setOverrideDeadline

如果jobInfo配置如下

                    JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
                            .setPeriodic(2000)
                            .setOverrideDeadline(10000)
                            .build();

运行程序会报错

java.lang.IllegalArgumentException: Can't call setOverrideDeadline() on a periodic job.

如果我去掉setPeriodic(2000)这行代码,在运行程序,我发现点击一次按钮就会立即启动任务,也就是弹出Toast,但是后面会继续启动任务,只是间隔时间比10秒时间要长得多

现在JobInfo代码我写成如下

                    JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
                            .setOverrideDeadline(5000)
                            .setMinimumLatency(3000)
                            .build();
程序运行正常,符合预期
setPersisted

setPersisted不是一个主约束条件,当JobInfo代码如下

                    JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
                            //.setMinimumLatency(10000)
                            .setPersisted(true)
                            .build();

按下按钮,然后重启手机,没有效果。。。。。

setRequiresDeviceIdle

代码如下

                    JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
                            .setRequiresDeviceIdle(true)
                            .build();

额,手机空闲状态,明明其他手机程序都退出来,半天等不到,

(3)JobSheduler任务调度

之前我们在基础代码里看到了以下代码,就是判断任务是否创建成功,但是这还不是任务调度的范围

                    if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
                        //If something goes wrong
                    }

首先我们看看cancel函数的效果,activity的代码里加一个button,为了触发cancel函数

public class MainActivity extends AppCompatActivity {


    Button btn, btn_pause;
    private JobScheduler mJobScheduler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn = (Button) findViewById(R.id.btn);
        btn_pause = (Button) findViewById(R.id.btn_pause) ;
        mJobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    JobInfo.Builder builder = new JobInfo.Builder( 1,
                            new ComponentName( getPackageName(), MyJobService.class.getName() ) );
                    builder.setMinimumLatency(20000);
                    if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
                        //If something goes wrong
                    }

                }

            }
        });

        btn_pause.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    mJobScheduler.cancel(1);
                }
            }
        });

    }


}

运行程序,点击第一个按钮,然后再点击第二个按钮,确认任务没有被启动过,把cancel函数缓存cancelAll效果一样

其实还有函数可以看到未执行任务的函数,比如getPendingJob,但是这一个需要手机系统是Android7.0以上的


参考文章:

https://blog.csdn.net/qq_33689414/article/details/54668889

https://blog.csdn.net/bboyfeiyu/article/details/44809395

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值