IntentService - 非同期、自動終了、キュー・・・便利なサービスの実装
サービスの実装にかかわる問題点、注意点は 単純なサービス などで説明しました。
ポイントは、サービスの処理はそれを起動するスレッドとは別の作業用スレッドで行うべき、処理終了時は明示的にサービスを stopService (または stopSelf) で終了状態にするなどです。
作業用のワーカースレッドを作り、そこで作業を行うのは一般的に煩雑な処理になりがちなのですが、サービスの実装においては IntentService を利用することで非常に簡単に実装することができます。
IntenetService の利用方法
IntentService を利用するには Service クラスではなく、次のように IntentService クラスを派生します。 そしてサービス固有の、一般的に時間のかかる処理を onHandleIntent で行います。
package com.keicode.android.test;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
public class MyIntentService extends IntentService {
final static String TAG = "MyIntentService";
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
try {
Log.d(TAG, "onHandleIntent");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
上記を呼び出すと次のようなログが記録されます。
onHandleIntent はひとつのワーカースレッドで処理される
onHandleIntent はメインスレッドではなく、専用のワーカースレッド (worker thread) で処理されます。コンストラクタに渡した文字列は、このワーカースレッドの名前になります。
上記コードを実行時にデバッガでスレッドをみてみると、確かにコンストラクタに渡した名前がスレッドの名前になっていることが確認できます。
IntentService が複数ある場合は、この名前でそれぞれを区別するとよいでしょう。
順次処理 -「ワークキュープロッセサ」パターン
ひとつのワーカースレッドで処理をするために、onHandleIntent メソッド実行時にさらに同サービスの開始リクエストが行われた場合は、 その要求はただちには処理されずキューに置かれます。
こうした処理の流れ・パターンを "ワークキュープロセッサ" (work queue processor) パターンなどといいます。
キュー内の処理が全て終わるとサービス停止
onHandleIntent が実行し終わったときに、ワークキューをチェックして、待ち作業がないときに、onDestroy が呼ばれます。
一回の onHandleIntent に対応して一度ずつ onDestroy が呼ばれるわけではないことに注意が必要です。必要なクリーンアップ処理は onDestory にまとめないで、 onHandleIntent 内で行うことも検討すべきかもしれません。
明示的にサービスを停止する必要なし
上で書いた通り、サービスの停止はキュー内の作業が全て終わったときに自動的に行われます。これは stopService や stopSelf を明示的に呼ばなくても行われます。
stopService あるいは stopSelf を呼ぶ必要が無いため、Service を直接派生したときにしなければならないサービスの止め忘れを未然に防ぐことができます。
以上説明した通り、IntentService はかなり便利なのでサービス実装時には利用を検討すべきでしょう。