読者です 読者をやめる 読者になる 読者になる

BroadcastReceiverの処理結果を受け取る方法

BroadcastReceiverの処理結果が取れる?

ある日、BroadcastReceiver.setResult()があることに気がついた。 ずっとBroadcastの結果は取れないものだと思っていたが、Context.sendOrderedBroadcast()を使用することでその結果を受け取ることができるようだ。

概要

大まかな処理手順はこうだ。 まず、sendOrderedBroadcast()ではBroadcastReceiverがその優先順位にしたがって呼び出される。 それぞれのBroadcastReceiveronReceive()の最後にsetResult()によって処理結果を追記する。 sendOrderedBroadcast()では一番最後に処理を行うBroadcastReceiverを直接指定することができるため、そのonReceive()の中でgetResultCode(),getResultData(),getResultExtras()を参照することですべてのBroadcastの最終的な処理結果を受け取ることができる。

優先順位設定

Broadcastの優先順位はIntentFilter.setPriority()で行う。 数字の大きいものが優先度が高く、デフォルトは0。 おそらくIntentFilter.SYSTEM_HIGH_PRIORITYからIntentFilter.SYSTEM_LOW_PRIORITYの間で設定したほうが良いと思う。

BroadcastReceiver receiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MY_ACTION);
// 優先度を高めに設定
intentFilter.setPriority(100);
registerReceiver(receiver, intentFilter);

BroadcastReceiverの実装

BroadcastReceiver側の処理はsetResult系の処理をする事以外は何もしなくて良い。 先に実行されたBroadcastReceiverの処理結果はgetResultCode(),getResultData(),getResultExtras()で取得できる。 setResult()した場合、値はすべて上書きされることに注意

    @Override
    public void onReceive(Context context, Intent intent) 
    {
        // onReceive処理

        // 前のBroadcastReceiverの判定を引き継ぐ
        setResultCode(getResultCode());

        // Extrasに何か入れてみる
        // 引数をtrueにするとnullの場合自動生成してくれる
        Bundle extras = getResultExtras(true);
        extras.putString("key", "value");
        setResultExtras(extras);
    }

何らかの理由で以降のBroadcastReceiverを実行しないようにするにはabortBroadcast()で以降のBroadcastに処理が伝達されないようにすれば良い。 ただし、確実に止められるのは自分より優先度が低いBroadcastReceiverのみとなる。 優先度が等しいBroadcastReceiverは自分より前に実行されている可能性があるため。

    @Override
    public void onReceive(Context context, Intent intent) 
    {
        // onReceive処理

        if(FAILED){
            // 失敗したのでこのReceiverで処理を終了したい

            // RESULT_CANCELEDにするのが良いかも?
            setResultCode(Activity.RESULT_CANCELED);

            // これより優先順位が低いBroadcastReceiverは実行されない
            abortBroadcast();
        }
    }

Broadcastの送信

Context.sendOrderedBroadcast()は2種類あるが、処理結果を扱えるのは1種類)だけだ。 引数が多いが、第3引数のresultReceiverが最後に実行されるBroadcastReceiverになる。initial〜系の引数は処理結果のデフォルト値を格納する。

public abstract void sendOrderedBroadcast (Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)

結果は当然、resultReceiverに指定したBroadcastReceiverで受け取る。 abortBroadcast()された場合でもresultReceiverは実行されるようだ。 (IntentFilterでBroadcastを受信しているわけではないので当然か)

    @Override
    public void onReceive(Context context, Intent intent) 
    {
        // 処理結果
        getResultCode();
        getResultData();
        getResultExtras(false);
    }

まとめ

便利そうだけど使い道が思いつかない。 システムならともかく、アプリでどう使うべきなんだろう。