search
LoginSignup
15

More than 3 years have passed since last update.

posted at

updated at

JobDispatcherを使ってみる

JobDispatcherとは

firebase/firebase-jobdispatcher-android

APILevel 21(Lollipop)で追加されたJobSchedulerの代替ライブラリです。完全に忘却の彼方でしたが、Google IO 2016で紹介されていたみたいです。
JobSchedulerの代替であることからわかるようにタスクスケジューラとして利用するものです。

JobDispatcherのバックエンドはGooglePlayServicesGCMNetworkManagerに依存してます。一応実装が抽象化されていますが、現状はGCMNetworkManagerのラッパーと考えて良さそうです。

本稿ではJobSchedulerの話はしませんが、JobDispatcherJobSchedulerと同じインターフェースではないということに注意してください。

そもそも何故生まれたか

Android 7.0では、android.net.conn.CONNECTIVITY_CHANGEを始めとするいくつかのブロードキャストについて、BroadcastReceiver.register()以外の方法でブロードキャストを受信できなくなります。(Manifestに書いたやつはダメということ)

android.net.conn.CONNECTIVITY_CHANGEはネットワーク状態の変更を通知してくれますが、この条件が雑すぎたことで送信頻度が高いため、システムがバックグラウンドで多くのアプリを起動する(BroadcastReceiverが起動される=アプリが起動する)ことに繋がっていました。
多くのアプリは、「通信できるようになれば、xxする」という目的に使われているはずですが、「通信可能|不可能状態への変化」「Wi-Fi|モバイル回線切り替え」など、様々な条件で飛ぶようになっているので、やべえよやべえよ…ってことのようです。

できること

現状、githubにあるドキュメントが雑なので、GCMNetworkManagerのドキュメントも合わせて参考にしたほうがいいかもしれないです。
ただ、これらの機能がすべてJobDispatcherで提供されているのかは調べ切れてないです。

  1. 1回または繰り返しのタスクスケジュールを提供
  2. エラー時の再試行及びバックオフのサポート
  3. 端末状態の条件付与 (ネットワーク状況、Wi-Fi only、充電状態限定)
  4. ジョブの永続性 (端末再起動、アプリアップデートなどに対応)

特に1は、場合によってはAlarmManagerいらねえんじゃねえかなとか思ったりしました。

利用

dependenciescom.google.android.gms:play-services-gcmを含んでいるか否かでわかれます。要するに、単品とplay-services-gcmバンドル版があるということです。

単品

compile 'com.firebase:firebase-jobdispatcher:{latestVersion}'

バンドル版

compile 'com.firebase:firebase-jobdispatcher-with-gcm-dep:{latestVersion}'

実装

JobDispatcherを利用するために必要な実装は、主に2つに分かれています。

  1. JobServiceの実装
  2. Jobの構築

JobServiceの実装

JobServiceは名前の通り、AndroidのServiceのことです。
JobDispatcherで、JobServiceSimpleJobServiceというクラスが提供されているので、どちらかを継承しましょう。

MyJobService.java
public class MyJobService extends SimpleJobService {

    @Override
    public int onRunJob(JobParameters job) {
        // any
    }
}

JobServiceSimpleJobServiceの違いですが、コード見た感じだとServiceIntentServiceのようなものです。SimpleJobServiceは専用スレッドでonRunJob()メソッドが呼び出されます。

JobServiceを用意したら、忘れずにManifestに追加しましょう。1

AndroidManifest.xml
<application><service
        android:name=".MyJobService"
        android:exported="false">

        <intent-filter>
            <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
        </intent-filter>
    </service>

</application>

Jobの構築

ジョブの実行条件はJobインスタンスを構築して行います。Jobの構築にはFirebaseJobDispatcherを使います。
FirebaseJobDispatcherの実装は抽象化されており、DriverインターフェースでDelegateできます。ただ、プリセットとして実装されているのはGooglePlayDriverしかないため、基本おまじないになります。

FirebaseJobDispatcher dispathcer = new FirebaseJobDispatcher(new GooglePlayDriver(context));

FirebaseJobDispatcherから、JobのBuilderを生成できます。

Job.Builder jobBuilder = dispatcher.newJobBuilder()
        .setService(MyJobService.class)
        .setTag("myJob")
        .setTrigger(Trigger.NOW)
        .setReplaceCurrent(true);
メソッド 用途 備考
setService(Class) 起動するServiceの指定
setTag(String) ジョブを識別するIDを設定する 100文字以内
setTrigger(JobTrigger) 着火猶予の指定 30秒未満は30秒になる(?)
setLifetime(int) 永続性の指定 端末を再起動しても持続するかどうか
setRecurring(boolean) 繰り返しの設定 Trigger.NOWでは使えない
setConstraints(int...) 端末状態条件の指定
setRetryStrategy(RetryStrategy) 再試行間隔のバックオフアルゴリズムの指定
setReplaceCurrent(boolean) 既存の同tagのジョブに対して上書きを行うかどうか
setExtras(Bundle) タスクに渡す任意のBundle

Jobを構築したら、あとは登録するだけです。

dispatcher.schedule(jobBuilder.build());

ちなみにJobの取り消しはtagで行います。

dispatcher.cancel(tag);

定期的に繰り返す

Jobを繰り返すのは、setRecurring(true)とするだけですが、このときsetTrigger()には、ExecutionWindowTriggerを指定する必要があります。

FirebaseJobDispatcher dispathcer = new FirebaseJobDispatcher(new GooglePlayDriver(context));

Job.Builder jobBuilder = newJobDispatcher(this).newJobBuilder()
        .setTag("myPeriodicJob")
        .setService(MyJobService.class)
        .setRecurring(true)
        .setTrigger(Trigger.executionWindow(60, 120));

dispatcher.schedule(jobBuilder.build());
Trigger.executionWindow(60, 120)

この記述の場合、60~120秒程度のスパンで、ジョブを繰り返し実行するという指定になります。

即座に実行する

Trigger.NOWという指定を行うと、直近で1回だけ行うタスクを実行するジョブを作れます。しかし、これにも30秒制限があるようで、実際には即座に実行されず30秒程あとに実行されます

つまり、即時実行のジョブは作れないということになります。

Trigger.NOWの遅延を1秒に変更したよ!っていうPRがマージされていたので、早くて30秒後ではなくなったかもしれないです

Bug fix and speed up Trigger.NOW by unEgor · Pull Request #174 · firebase/firebase-jobdispatcher-android

ジョブの保留

ネットワーク状態や端末状態を条件にした場合(setConstraints())、条件を満たしていないと、時間になってもジョブが実行されず保留されます。保留されたジョブは条件を満たしたときに実行されます。

参考

firebase/firebase-jobdispatcher-android

Implementing GCM Network Manager on Android | Google Developers


  1. カスタムIntentFilterを書いているとデフォでexported=trueになってセキュリティ的にあうあうあーってなるので注意してください 

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
15