45

ジョブ スケジューラは、Android Marshmallow および Lollipop デバイスでは期待どおりに動作しますが、Nexus 5x (Android N プレビュー) では実行されません。

ジョブをスケジュールするためのコード

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

サービスはマニフェストで次のように定義されています。

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

Android N (プレビュー) でこの問題が発生している人はいますか?

4

4 に答える 4

60

Android Nougat では、定期的なジョブをスケジュールsetPeriodic(long intervalMillis)するためにメソッド呼び出しが利用されます。setPeriodic (long intervalMillis, long flexMillis)

ドキュメントに従って:

JobInfo.Builder setPeriodic (長い intervalMillis、長い flexMillis)

このジョブが指定された間隔とフレックスで繰り返されるように指定します。ジョブは、期間の終わりにフレックス長のウィンドウでいつでも実行できます。

intervalMillis long: このジョブが繰り返されるミリ秒間隔。getMinPeriodMillis() の最小値が適用されます。

flexMillis long: このジョブのミリ秒のフレックス。Flex は、少なくとも getMinFlexMillis() または期間の 5% のいずれか高い方になるようにクランプされます。

5 秒間スケジュールされた定期的なジョブの例:

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

上記のコードは Lollipop と Marshmallow では問題なく動作しますが、Nougat で実行すると、次のログが表示されます。

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

定期的な更新間隔を 5 秒に設定したため、しきい値よりも小さくなっていgetMinPeriodMillis()ます。Android Nougat は、getMinPeriodMillis().

回避策として、次のコードを使用して、ジョブの間隔が 15 分未満の場合に定期的な間隔でジョブをスケジュールしています。

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

サンプル 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);
    }
}
于 2016-08-04T17:45:12.043 に答える
17

現状を打破しようとする人がいたら、

>= Android N の回避策は次のとおりです (定期ジョブを 15 分未満に設定する場合)

setMinimumLatency のみが使用されていることを確認します。また、時間がかかるタスクを実行している場合、次のジョブは現在の JOB 終了時間 + PROVIDED_TIME_INTERVAL にスケジュールされます。

.SetPeriodic(long millis) は、Android N より下の API レベルでうまく機能します

@Override
public boolean onStartJob(final JobParameters jobParameters) {
    Log.d(TAG,"Running service now..");
    //Small or Long Running task with callback
    //Call Job Finished when your job is finished, in callback
    jobFinished(jobParameters, false );

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



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

更新: 繰り返しジョブをDoze モードで実行し、JobScheduler について検討している場合、FYI: JobSchedulers は Doze モードで実行できません。

JobScheduler について話していたので、Dozing については説明しませんでした。@Elletlarに感謝します。アプリが居眠りモードの場合でも実行されると考える人もいるかもしれませんが、そうではありません。

居眠りモードの場合でも、AlarmManager が最適なソリューションを提供します。定期的なジョブを正確な時間帯に実行する場合はsetExactAndAllowWhileIdle()を使用し、柔軟性がある場合はsetAndAllowWhileIdle()を使用できます。

デバイスは常に目覚まし時計の居眠りモードから抜け出し、再び居眠りモードに戻るため、setAlarmClock()を使用することもできます。別の方法は、FCM を使用することです。

于 2017-12-11T20:21:29.843 に答える