2016-03-21 25 views
13

Używam poniższy kod do tworzenia i zaplanować pracę używając Androidy JobScheduler API:Android JobScheduler wykonywania kilkakrotnie

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

tj okresowe zadanie, które wykonuje się co 2 godziny, a liniowa polityka wycofania, która wykonuje 20-minutową liczbę, nie powiedzie się w przypadku niepowodzenia zadania.

Moja praca kod serwisowy jest napisane jak poniżej:

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

} 

I wreszcie wyjście dziennika jest jak poniżej:

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

Dlaczego onStartJob są nazywane dwa razy?

Odpowiedz

11

Po wielu frustracjach zorientowałem się, co powoduje ten problem.

Powinieneś nie zadzwonić pod numer jobFinished(JobParameters, true) w sprawie okresowej pracy. Przekazanie true dla needsReschedule spowoduje duplikowanie zadania w kolejce (można się spodziewać, że nadpisze oryginalną, ale najwyraźniej tak nie jest). Zawsze musisz używać jobFinished(JobParameters, false), nawet jeśli twoje zadanie się nie powiedzie.

Jeśli chodzi o to, czy jest to nieprawidłowe użycie API, czy błąd Androida, pozostawiam to Tobie.

+1

Wow, ładny połów. Miałem aplikację, która miała zaplanowaną pracę 15 minut kilka razy na minutę po kilku tygodniach instalacji. Jeśli to, co mówisz, jest prawdą, oznacza to, że za każdym razem, gdy nie udało się nawiązać połączenia sieciowego, pojawiła się nowa okresowa praca. – Tom

0

Od JobScheduler zostaną wykorzystane dużo więcej z Androidem Oreo, chciałem opisać kilka problemów na przykładzie:

onStopJob() zastąpiona metoda zwraca tylko true. Jeśli twoje zadanie zostanie przerwane w trakcie przetwarzania, tzn. Ładowarka jest odłączona lub nie ma sieci ustawionej w JobInfo, funkcja ta powinna być również użyta do natychmiastowego anulowania zadania/zadania. Następnie powinien powrócić true wskazując, że należy przesunąć zadanie.

MyJobService powinien mieć odniesienie private do zadania MyWorker. onStartJob() ustawia. onStopJob() używa go do natychmiastowego anulowania zadania.

Przekazywanie true dla needsReschedule w ramach metody jobFinished() jest generalnie niepotrzebne, szczególnie gdy jest wywoływane w ramach zadania. Jeśli zadanie zostanie przerwane, funkcja onStopJob() zostanie wywołana, aby anulować, a zwracanie wartości true spowoduje jej przełożenie. Widziałem tylko jeden przykład here, gdzie needsReschedule jest ustawiony na true. Jest w zakresie onStartJob() i jeśli podwójne sprawdzanie warunków wstępnych nie jest spełnione, jobFinished(args, true), a następnie return false zamiast true.

Mam nadzieję, że to pomoże!

Powiązane problemy