web-dev-qa-db-fra.com

Android Job Scheduler - Job programmé à exécuter immédiatement et exactement une fois

J'essaie d'utiliser le planificateur de tâches Android pour planifier l'exécution d'une tâche immédiatement et exactement une fois.

        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

        jobScheduler.cancel(1);

        PersistableBundle bundle = new PersistableBundle();
        bundle.putInt(JobFlags.KEY_PERIODIC_SYNC_JOB, JobFlags.JOB_TYPE_INITIAL_FETCH);

        jobScheduler.schedule(new JobInfo.Builder(1,
                new ComponentName(context, SyncJobLollipop.class))
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                .setExtras(bundle)
                .setMinimumLatency(10)
                .setOverrideDeadline(24 * 3600 * 1000)
                .build());

Mais il court environ 3 4 fois. Qu'est-ce qui ne va pas ici?

Voici la classe d'emploi elle-même:

@RequiresApi(api = Build.VERSION_CODES.Lollipop)
public class SyncJobLollipop extends JobService implements JobFinishedListener {

    @Inject
    SyncJobBackend jobBackend;

    private JobParameters jobParameters;

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        ((MyApplication)getApplication()).getAppComponent().inject(this);
        this.jobParameters = jobParameters;
        PersistableBundle bundle = jobParameters.getExtras();
        int type = bundle.getInt(JobFlags.KEY_PERIODIC_SYNC_JOB);
        jobBackend.onStartJob(type, this);
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        jobBackend.onStopJob();
        return false;
    }

    @Override
    public void onJobFinished(boolean success) {
        jobFinished(jobParameters, !success);
    }

}

P.S .: J'ai vérifié que je suis callig jobFinished avec une fausse valeur à chaque fois.

7
dumb_terminal

Pour exécuter le travail exactement une fois, vous devez exécuter votre code dans onStartJob(...) dans un travailleur en arrière-plan et supprimer ses rappels lorsque onStopJob(...) est appelé.

public class SyncJobLollipop extends JobService {
    final Handler workHandler = new Handler();
    Runnable workRunnable;

    @Override
    public boolean onStartJob(JobParameters params) {
        workRunnable = new Runnable() {
            @Override
            public void run() {
                // do your work here,
                // such as jobBackend.onStartJob(type, this)

                boolean reschedule = false;
                jobFinished(params, reschedule);
            }};
        workHandler.post(workRunnable);
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        workHandler.removeCallbacks(workRunnable);
        return false;
    }
}

Pour l'exécuter immédiatement, vous devez définir "latence minimale" et "délai de dépassement" sur 1.

jobScheduler.schedule(new JobInfo.Builder(1,
            new ComponentName(context, SyncJobLollipop.class))
            .setExtras(bundle)
            .setMinimumLatency(1)
            .setOverrideDeadline(1)
            .build());

Veuillez noter que le mode Doze du système d'exploitation peut différer les tâches de JobScheduler jusqu'à ce qu'une "période de maintenance" ou que le périphérique soit réveillé d'une autre manière. Toutefois, le code ci-dessus ne fonctionnant que dans/en dehors/du mode Doze, le travail doit donc être planifié presque sans délai.

4
intrepidis