Help us understand the problem. What is going on with this article?

スリープ時にも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を処理することはよくあるので、ぜひ覚えておきたい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした