スリープ時にもBroadcastを処理する方法

More than 3 years have passed since last update.


スリープとBroadcast

端末がスリープ状態の場合でもBroadcastReceiver.onReceive()の呼び出しは通常どおり行われる。

ただし、onReceive()からServiceを呼び出して処理させる場合、その処理が中断されてしまう可能性がある。

確実にバックグラウンド処理を行うためには、Wakelockによってスリープ状態を制御する必要がある。

この処理は通常、ServiceWakelockを扱う場合、PowerManagerを使って以下の様に記述する。


AndroidManifest.xml

<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記述も必要となる。


AndroidManifest.xml

<uses-permission android:name="android.permission.WAKE_LOCK" />

<receiver android:name=".MyBroadcastReceiver">
...
</receiver>
<service android:name=".MyService" />

サービスの起動にはstartServiceではなくstartWakefulServiceを使用する。

このメソッドは内部でstartServiceを呼んだあとWakelock.acquire()でスリープ制御を行っている。


MyBroadcastReceiver.java

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を引数に入れること。


MyService.java

public class MyService extends IntentService {

public MyService() {
super("MyService");
}

@Override
protected void onHandleIntent(final Intent intent) {
try {
// サービス内部の処理
} finally {
// Wakelockの解除処理が必ず呼ばれるようにしておく
WakefulBroadcastReceiver.completeWakefulIntent(intent);
}
}
}



まとめ

コード量を大幅に削減できてID管理とかも裏でやってくれるのは楽だ。

スリープ時にBroadcastを処理することはよくあるので、ぜひ覚えておきたい。