スリープ時にもBroadcastを処理する方法
スリープとBroadcast
端末がスリープ状態の場合でもBroadcastReceiver.onReceive()
の呼び出しは通常どおり行われる。
ただし、onReceive()
からService
を呼び出して処理させる場合、その処理が中断されてしまう可能性がある。
確実にバックグラウンド処理を行うためには、Wakelock
によってスリープ状態を制御する必要がある。
この処理は通常、Service
でWakelock
を扱う場合、PowerManager
を使って以下の様に記述する。
<uses-permission android:name="android.permission.WAKE_LOCK" />
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE); Wakelock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK , "MyWakelockTag"); // wakeLock開始 wakeLock.acquire(); // 処理 // wakeLock解除 wakeLock.release();
これでも問題なく動くのだが、Androidではスリープ時にBroadcastを扱うための便利な仕組みが用意されている。
WakefulBroadcastReceiver
WakefulBroadcastReceiver
はSupport Libraryに含まれるBroadcastReceiver
のサブクラスである。
スリープ状態でService
を扱うためのメソッドが二つ追加されている。
https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html
Manifest記述は通常のBroadcastReceiver
と変わらない。
当然、Manifestへのuses-permission
記述も必要となる。
<uses-permission android:name="android.permission.WAKE_LOCK" /> <receiver android:name=".MyBroadcastReceiver"> ... </receiver> <service android:name=".MyService" />
サービスの起動にはstartService
ではなくstartWakefulService
を使用する。
このメソッドは内部でstartService
を呼んだあとWakelock.acquire()
でスリープ制御を行っている。
public class MyBroadcastReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent serviceIntent = new Intent(context,MyService.class); // サービス起動 startWakefulService(context,serviceIntent); } }
サービス側では処理の終了時に必ず呼び出し元BroadcastReceiverのcompleteWakefulIntent()
を呼ぶ。
また、startWakefulService()
ではIntent.putExtra()
でwakelock制御IDをIntent
に追記しているため、Service
起動時のIntent
を引数に入れること。
public class MyServiceextends IntentService { public MyService() { super("MyService"); } @Override protected void onHandleIntent(final Intent intent) { try { // サービス内部の処理 }finally { // Wakelockの解除処理が必ず呼ばれるようにしておく MyBroadcastReceiver.completeWakefulIntent(intent); } } }
まとめ
コード量を大幅に削減できてID管理とかも裏でやってくれるのは楽だ。
スリープ時にBroadcastを処理することはよくあるので、ぜひ覚えておきたい。
しかし、BroadcastReceiver
とService
の結合が強くなってしまうのは良いんだろうか…。
Servcie
を使い回したい場合はどうするんだろう。継承?