Android JobScheduler 执行多次

2022-09-01 21:00:12

我正在使用以下代码来创建和安排使用Androids JobScheduler API的作业:

Log.d("hanif", "Scheduling periodic job 2 hrs with 20 mins backoff linear");

JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
            new ComponentName(getApplicationContext(), MyJobService.class))
            .setPeriodic(TimeUnit.HOURS.toMillis(2))
            .setRequiresCharging(true)
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
            .setBackoffCriteria(TimeUnit.MINUTES.toMillis(20),
                                        JobInfo.BACKOFF_POLICY_LINEAR)
            .build();
JobScheduler scheduler = 
                (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);

即,每 2 小时执行一次的定期作业和在作业失败时执行 20 分钟 * 数字的线性回退策略将失败。

我的工作服务代码编写如下:

public class MyJobService extends JobService {

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        Log.d("hanif", "onStartJob");
        new MyWorker(getApplicationContext(), this, jobParameters).execute();
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        Log.d("hanif", "onStopJob");
        return true;
    }

    private static class MyWorker extends AsyncTask<Void, Void, Boolean> {
        private final Context mContext;
        private final MyJobService mJobService;
        private final JobParameters mJobParams;

        public MyWorker(Context context, MyJobService myJobService, JobParameters jobParameters) {
            mContext = context;
            mJobService = myJobService;
            mJobParams = jobParameters;
        }

        @Override
        protected Boolean doInBackground(Void... voids) {
            Log.d("hanif", "Work start!");
            for (int i=0; i<999999999; i++) {}
            int counter = Prefs.getCounter(mContext);
            Log.d("hanif", "Work done! counter: " + counter);
            if (counter == 3) {
                Log.d("hanif", "DO RESCHEDULE");
                Prefs.resetCounter(mContext);
                return true;
            }
            Log.d("hanif", "DO NOT RESCHEDULE");
            Prefs.increaseCounter(mContext);
            return false;
        }

        @Override
        public void onPostExecute(Boolean reschedule) {
            if (reschedule) {
                mJobService.jobFinished(mJobParams, true);
            } else {
                mJobService.jobFinished(mJobParams, false);
            }
            Log.d("hanif", "------------------------------------------");
        }
    }

}

最后,日志输出如下:

03-27 12:57:11.677  7383  7383 D hanif   : Scheduling periodic job 2 hrs with 20 mins backoff linear
03-27 12:57:31.904  7383  7383 D hanif   : onStartJob
03-27 12:57:31.909  7383  8623 D hanif   : Work start!
03-27 12:57:42.110  7383  8623 D hanif   : Work done! counter: 0
03-27 12:57:42.111  7383  8623 D hanif   : DO NOT RESCHEDULE
03-27 12:57:42.125  7383  7383 D hanif   : ------------------------
03-27 14:58:50.786  7383  7383 D hanif   : onStartJob
03-27 14:58:50.789  7383 21490 D hanif   : Work start!
03-27 14:59:00.952  7383 21490 D hanif   : Work done! counter: 1
03-27 14:59:00.953  7383 21490 D hanif   : DO NOT RESCHEDULE
03-27 14:59:00.962  7383  7383 D hanif   : ------------------------
03-27 16:57:12.021  7383  7383 D hanif   : onStartJob
03-27 16:57:12.045  7383 32028 D hanif   : Work start!
03-27 16:57:22.229  7383 32028 D hanif   : Work done! counter: 2
03-27 16:57:22.230  7383 32028 D hanif   : DO NOT RESCHEDULE
03-27 16:57:22.238  7383  7383 D hanif   : ------------------------
03-27 18:57:11.984  7383  7383 D hanif   : onStartJob
03-27 18:57:11.989  7383 13217 D hanif   : Work start!
03-27 18:57:22.123  7383 13217 D hanif   : Work done! counter: 3
03-27 18:57:22.124  7383 13217 D hanif   : DO RESCHEDULE
03-27 18:57:22.130  7383  7383 D hanif   : ------------------------
03-27 19:20:57.468  7383  7383 D hanif   : onStartJob
03-27 19:20:57.482  7383  1913 D hanif   : Work start!
03-27 19:21:07.723  7383  1913 D hanif   : Work done! counter: 0
03-27 19:21:07.724  7383  1913 D hanif   : DO NOT RESCHEDULE
03-27 19:21:07.733  7383  7383 D hanif   : ------------------------
03-27 19:21:57.669  7383  7383 D hanif   : onStartJob  <--- Why is this called again?
03-27 19:21:57.675  7383  3025 D hanif   : Work start!
03-27 19:22:07.895  7383  3025 D hanif   : Work done! counter: 1
03-27 19:22:07.896  7383  3025 D hanif   : DO NOT RESCHEDULE
03-27 19:22:07.906  7383  7383 D hanif   : ------------------------
03-27 21:40:53.419  7383  7383 D hanif   : onStartJob
03-27 21:40:53.423  7383 31526 D hanif   : Work start!
03-27 21:41:03.857  7383 31526 D hanif   : Work done! counter: 2
03-27 21:41:03.858  7383 31526 D hanif   : DO NOT RESCHEDULE
03-27 21:41:03.867  7383  7383 D hanif   : ------------------------

为什么onStartJob被调用了两次?


答案 1

在经历了很多挫折之后,我弄清楚了导致这个问题的原因。

不应调用定期作业。传递 将导致作业在队列中重复(您希望它覆盖原始作业,但显然情况并非如此)。即使任务失败,也必须始终使用 。jobFinished(JobParameters, true)trueneedsReschedulejobFinished(JobParameters, false)

至于这是否算作不正确的API使用或Android错误,我会把它留给你。


答案 2

由于JobScheduler将在Android Oreo中更多地使用,因此我想用这个例子来描述一些问题:

被覆盖的方法仅返回 。如果您的作业在处理过程中被中断,即充电器被拔出或没有JobInfo中设置的网络,则此函数也应用于立即取消任务/作业。然后,它应该返回,指示需要重新安排作业。onStopJob()truetrue

MyJobService应该有对任务的引用。 设置它。 使用它来立即取消任务。privateMyWorkeronStartJob()onStopJob()

通常不需要传递方法内部,尤其是在任务中调用时。如果作业中断,将调用 onStopJob() 来取消它,返回 true 将重新计划它。我在这里只看到一个设置为 .它是在内,如果不满足前提条件的双重检查,则代替 。trueneedsReschedulejobFinished()needsRescheduletrueonStartJob()jobFinished(args, true)return falsetrue

希望这有帮助!


推荐