web-dev-qa-db-ja.com

Android JobSchedulerを数回実行

以下のコードを使用して、Androids JobSchedulerAPIを使用してジョブを作成およびスケジュールしています。

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が2回呼び出されるのはなぜですか?

22
hanif

多くの欲求不満の後、私はこの問題の原因を突き止めました。

not定期的なジョブでjobFinished(JobParameters, true)を呼び出す必要があります。 trueneedsRescheduleを渡すと、ジョブがキューに複製されます(元のジョブが上書きされることが予想されますが、そうではないようです)。タスクが失敗した場合でも、常にjobFinished(JobParameters, false)を使用する必要があります。

これが誤ったAPIの使用としてカウントされるのか、Androidバグ)としてカウントされるのかについては、お任せします。

25
Andrew Sun

JobSchedulerはAndroid Oreoでより多く使用されるため、例でいくつかの問題を説明したいと思います。

onStopJob()オーバーライドされたメソッドは、trueのみを返します。処理中にジョブが中断された場合、つまり充電器が接続されていないか、JobInfoで設定されているネットワークがない場合は、この関数を使用してタスク/ジョブをすぐにキャンセルする必要があります。次に、ジョブを再スケジュールする必要があることを示すtrueを返す必要があります。

MyJobServiceには、privateタスクへのMyWorker参照が必要です。 onStartJob()はそれを設定します。 onStopJob()はこれを使用して、タスクをすぐにキャンセルします。

jobFinished()メソッド内のtrueneedsRescheduleを渡すことは、特にタスク内で呼び出される場合、通常は必要ありません。ジョブが中断された場合、onStopJob()が呼び出されてジョブがキャンセルされ、trueを返すとジョブが再スケジュールされます。私は1つの例しか見たことがありません ここ ここでneedsRescheduletrueに設定されています。これはonStartJob()内にあり、前提条件のダブルチェックが満たされない場合は、trueの代わりにjobFinished(args, true)を実行してからreturn falseを実行します。

お役に立てれば!

1
Steve Miskovetz