スリープと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);
}
}
サービス側では処理の終了時に必ずWakefulBroadcastReceiver.completeWakefulIntent()
を呼ぶ。
また、startWakefulService()
ではIntent.putExtra()
でwakelock制御IDをIntent
に追記しているため、Service
起動時のIntent
を引数に入れること。
public class MyService extends IntentService {
public MyService() {
super("MyService");
}
@Override
protected void onHandleIntent(final Intent intent) {
try {
// サービス内部の処理
} finally {
// Wakelockの解除処理が必ず呼ばれるようにしておく
WakefulBroadcastReceiver.completeWakefulIntent(intent);
}
}
}
まとめ
コード量を大幅に削減できてID管理とかも裏でやってくれるのは楽だ。
スリープ時にBroadcastを処理することはよくあるので、ぜひ覚えておきたい。