2016-03-21 22 views
13

Sto usando il codice qui sotto per creare e pianificare un processo utilizzando Androids JobScheduler API:Android JobScheduler esecuzione più volte

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

Vale a dire un lavoro periodico che viene eseguito ogni 2 ore e un criterio di retrocessione lineare che esegue un numero di 20 min * non riesce nel caso in cui il lavoro non vada a buon fine.

Il mio lavoro codice di servizio è scritto come di seguito:

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", "------------------------------------------"); 
     } 
    } 

} 

E infine l'output del registro è la seguente:

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 : ------------------------ 

Perché onStartJob essere chiamato due volte?

risposta

11

Dopo molte frustrazioni, ho capito che cosa causa questo problema.

È necessario non chiamare jobFinished(JobParameters, true) in un lavoro periodico. Passando a true per needsReschedule, il lavoro verrà duplicato nella coda (ci si aspetterebbe che sovrascriva quello originale, ma apparentemente non è così). È sempre necessario utilizzare jobFinished(JobParameters, false), anche se l'attività non riesce.

Per quanto riguarda l'utilizzo errato dell'API o un bug Android, lo lascio a voi.

+1

Wow bella cattura. Avevo un'app con un lavoro programmato di 15 minuti in esecuzione più volte al minuto dopo alcune settimane di installazione. Se quello che dici è vero, allora stava generando un nuovo lavoro periodico ogni volta che falliva una chiamata di rete. – Tom

0

Dal JobScheduler verrà utilizzato molto di più con Android Oreo, ho voluto descrivere alcuni problemi con l'esempio:

Il onStopJob() metodo sovrascritto restituisce solo true. Se il lavoro viene interrotto mentre è in elaborazione, ovvero il caricabatterie è scollegato o non è collegato alla rete come impostato in JobInfo, questa funzione dovrebbe essere utilizzata per annullare immediatamente l'attività/il lavoro. Quindi dovrebbe restituire true indicando che il lavoro deve essere riprogrammato.

MyJobService deve avere un riferimento private all'attività MyWorker. onStartJob() lo imposta. onStopJob() lo utilizza per annullare immediatamente l'attività.

Il passaggio true per il needsReschedule all'interno del metodo jobFinished() in genere non è necessario in particolare quando viene chiamato all'interno dell'attività. Se un lavoro viene interrotto, onStopJob() verrà chiamato per annullarlo e restituire true lo ripianificherà. Ho visto solo un esempio here dove needsReschedule è impostato su true. È compreso tra onStartJob() e, se non viene soddisfatta la duplice verifica delle condizioni preliminari, jobFinished(args, true) e successivamente return false anziché true.

Spero che questo aiuti!

Problemi correlati