Harmonogram zadań nie działa na Androidzie N

Job Scheduler działa zgodnie z oczekiwaniami na urządzeniach z Androidem Marshmallow i Lollipop, ale nie działa i Nexus 5x (Android N Preview).

Kod do planowania zadania

        ComponentName componentName = new ComponentName(MainActivity.this, TestJobService.class.getName());
        JobInfo.Builder builder;
        builder = new JobInfo.Builder(JOB_ID, componentName);
        builder.setPeriodic(5000);
        JobInfo jobInfo;
        jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobInfo = builder.build();
        int jobId = jobScheduler.schedule(jobInfo);

Usługa jest zdefiniowana w manifeście jako:

<service android:name=".TestJobService"
            android:permission="android.permission.BIND_JOB_SERVICE" />

Czy ktoś ma ten problem na Androidzie N (Preview)?

Author: kaibuki, 2016-07-13

4 answers

W Androidzie Nougat setPeriodic(long intervalMillis) wywołanie metody wykorzystuje setPeriodic (long intervalMillis, long flexMillis) aby zaplanować okresowe zadania.

Zgodnie z dokumentacją:

JobInfo.Zestaw budowniczy (long intervalMillis, long flexMillis)

Określ, że zadanie to powinno się powtarzać z podanym interwałem i flex. Zadanie można wykonać w dowolnym momencie w oknie o długości flex w koniec okresu.

IntervalMillis long: Interwał milisekundowy, dla którego to zadanie będzie się powtarzać. Wymagana jest minimalna wartość getMinPeriodMillis ().

FlexMillis long: Milisekunda flex dla tej pracy. Flex jest zaciśnięty, aby wynosił co najmniej getMinFlexMillis() lub 5% okresu, w zależności od tego, która z tych wartości jest wyższa.

Przykładowe okresowe zadanie zaplanowane na 5 sekund:

private static final int JOB_ID = 1001;
private static final long REFRESH_INTERVAL  = 5 * 1000; // 5 seconds

JobInfo jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
        .setPeriodic(REFRESH_INTERVAL)
        .setExtras(bundle).build();

Powyższy kod działa dobrze w Lollipop & Marshmallow, ale po uruchomieniu w nugacie zauważysz następujący log:

W/JobInfo: Specified interval for 1001 is +5s0ms. Clamped to +15m0s0ms
W/JobInfo: Specified flex for 1001 is +5s0ms. Clamped to +5m0s0ms

Ponieważ ustawiliśmy okresowy interwał odświeżania na 5 sekund, co jest mniejsze niż próg getMinPeriodMillis(). Android Nougat wymusza getMinPeriodMillis().

Jako obejście używam poniższego kodu, aby zaplanować zadania w regularnych odstępach czasu, jeśli interwał jest krótszy niż 15 minut.

JobInfo jobInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
      .setMinimumLatency(REFRESH_INTERVAL)
      .setExtras(bundle).build();
} else {
  jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
      .setPeriodic(REFRESH_INTERVAL)
      .setExtras(bundle).build();
}

Przykładowy przykład usługi JobService:

public class SampleService extends JobService {
    @Override public boolean onStartJob(JobParameters params) {
        doSampleJob(params); 
        return true;
    }

    @Override public boolean onStopJob(JobParameters params) {
        return false;
    }

    public void doSampleJob(JobParameters params) {
        // Do some heavy operation
        ...... 
        // At the end inform job manager the status of the job.
        jobFinished(params, false);
    }
}
 52
Author: blizzard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-19 13:43:34

Jeśli ktoś nadal próbuje przezwyciężyć sytuację,

Oto obejście dla > = Android N (jeśli chcesz ustawić okresowe zadanie poniżej 15 minut)

Sprawdź, czy używany jest tylko setMinimumLatency. Ponadto, jeśli uruchamiasz zadanie, które zajmuje dużo czasu, następne zadanie zostanie zaplanowane na, bieżący czas zakończenia zadania + PROVIDED_TIME_INTERVAL

.SetPeriodic (long millis) działa dobrze dla poziomu API poniżej Android N

@Override
public boolean onStartJob(final JobParameters jobParameters) {
    Log.d(TAG,"Running service now..");
    //Small or Long Running task with callback

    //Reschedule the Service before calling job finished
    if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
              scheduleRefresh();

    //Call Job Finished
    jobFinished(jobParameters, false );

    return true;
}

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

private void scheduleRefresh() {
  JobScheduler mJobScheduler = (JobScheduler)getApplicationContext()
                    .getSystemService(JOB_SCHEDULER_SERVICE);
  JobInfo.Builder mJobBuilder = 
  new JobInfo.Builder(YOUR_JOB_ID,
                    new ComponentName(getPackageName(), 
                    GetSessionService.class.getName()));

  /* For Android N and Upper Versions */
  if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
      mJobBuilder
                .setMinimumLatency(60*1000) //YOUR_TIME_INTERVAL
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
  }

Aktualizacja: Jeśli zastanawiają się nad uruchomieniem powtarzającego się zadania w trybie drzemki i myślą o Jobschedulerze, dla twojej wiadomości: JobSchedulers nie mogą działać w trybie drzemki.

Nie dyskutowałem o drzemce, bo rozmawialiśmy o JobScheduler. Dzięki, @ Elletlar , za zwrócenie uwagi, że niektórzy mogą myśleć, że będzie działać nawet wtedy, gdy aplikacja jest w trybie drzemki, co nie jest w przypadku.

Dla trybu doze, AlarmManager nadal daje najlepsze rozwiązanie. możesz użyć setExactAndAllowWhileIdle() jeśli chcesz uruchomić swoje okresowe zadanie w dokładnym czasie lub użyj setAndAllowWhileIdle() jeśli jesteś elastyczny.

Możesz również użyć setAlarmClock() ponieważ urządzenie zawsze wychodzi z trybu drzemki dla budzika i wraca ponownie do trybu drzemki. Innym sposobem jest użycie FCM.

 10
Author: MRah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 15:09:59

Znalazłem odpowiedź na problem, z którym mamy do czynienia z urządzeniami Nugat. Urządzenia Nugat nie są w stanie zaplanować zadania, jeśli zadanie musi być ponownie zaplanowane mniej niż 15 minut.

Wypróbowałem, podając czas przerwy jako 15 minut, a praca zaczęła być planowana co 15 minut.

Kod Harmonogramu Pracy:

public static void scheduleJob(Context context) {
    ComponentName serviceComponent = new ComponentName(context, PAJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, serviceComponent);
    builder.setPeriodic(15 * 60 * 1000, 5 * 60 *1000);

    JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
    int ret = jobScheduler.schedule(builder.build());
    if (ret == JobScheduler.RESULT_SUCCESS) {
        Log.d(TAG, "Job scheduled successfully");
    } else {
        Log.d(TAG, "Job scheduling failed");
    }
}

Job Service:

public class PAJobService extends JobService {
    private static final String TAG = PRE_TAG + PAJobService.class.getSimpleName();
    private LocationManager mLocationManager;

    public boolean onStartJob(JobParameters params) {
        Log.d(TAG, "onStartJob");
        Toast.makeText(getApplicationContext(), "Job Started", Toast.LENGTH_SHORT).show();
        return false;
    }

    public boolean onStopJob(JobParameters params) {
        Log.d(TAG, "onStopJob");
        return false;
    }
}

Krótko mówiąc, jeśli zwiększyłbyś czas interwału do 15 minut, kod zacząłby działać.

private static final long REFRESH_INTERVAL = 15 * 60 * 1000;

 7
Author: Nandhan Thiravia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-15 13:13:30

Jeśli chcesz uruchomić kod okresowo mniej niż 15 minut, możesz użyć trudnego sposobu. Ustaw swój jobFinished() w ten sposób

jobFinished(parameters, true);

Przełoży Kod ze strategią ponownej próby. Definiowanie niestandardowych kryteriów cofania za pomocą

.setBackoffCriteria();
W budowniczym. Następnie będzie działać okresowo
 0
Author: MarGin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 08:47:42