背景
Android Oreoのリリースにより、従来バックグラウンド上常に動くServiceは動かなくなるため、対応しました。以下はその対応の記載です。
Android Oreo Background Limit
対応策
Serviceはそのまま使えないので、Androidドキュメントに勧められたJobSchedulerを使って、実装しようと思います。
選択肢として以下のライブラリがあります。
ちなみに、android-jobというevernoteが作ったライブラリもありますが、WorkManagerは同じ実装をしたようです。
その中でできればAPIレベル低い、かつ柔軟に対応してくれるのは基準としてWorkManagerを選びました。
メリット
- API 14+
- No require Google Play Service
- Googleが出している
- 端末のOSバージョンとアプリのtargetSdkVersionにより、柔軟に対応してくれる
デメリット
- WorkManagerはまだalpha版
実装
- Workerを実装
public class MyWorker extends Worker {
public static final String TAG = MyWorker.class.getSimpleName();
@NonNull
@Override
public Result doWork() {
LogUtil.debug(TAG, "Start My Worker");
try {
MYTracking myTracking = MyTracking.getInstance(getApplicationContext());
myTracking.start();
}
catch (Exception e) {
e.printStackTrace();
// TODO: deal with exception
return Result.RETRY;
}
return Result.SUCCESS;
}
}
- Trackingクラスを実装
public class MyTracking {
private MyTracking() {
}
public static MyTracking getInstance(Context _context) {
context = _context;
return instance;
}
public void start() {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
LogUtil.e(TAG, "Need ACCESS_FINE_LOCATION permission to start MyWorker!");
return;
}
// 制約を設定する
Criteria criteria = new Criteria();
criteria.setSpeedRequired(false);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
String bestProvider = locationManager.getBestProvider(criteria, true);
LogUtil.debug(TAG, "The best provider is: " + bestProvider);
Looper looper = Looper.getMainLooper();
MyListener myListener = new MyListener(context);
locationManager.requestSingleUpdate(bestProvider, myListener, looper);
}
}
- Mainのcreateメソッドの中からWorkerを呼び出す
private void startTracking() {
Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(MyWorker.class, REPEAT_INTERVAL, TimeUnit.MINUTES).setConstraints(constraints).addTag(MyWorker.TAG).build();
// すでにMyWorkerが存在している場合は、入れ替えます。
WorkManager.getInstance().enqueueUniquePeriodicWork("MyWorker", ExistingPeriodicWorkPolicy.REPLACE, request);
}
感想
WorkManagerを使ってバックグラウンドジョブの実装は大分楽になりました。