BroadcastReceiver

1.1概説

BroadcastとBroadcast Receiverはイベントを報告する仕掛けの一つです。

この仕掛けを図1.1に示します。

 

 

 

 

 

 

 

 

 


図1.1 Broadcastのしくみ

 

イベントが起きるとその旨をbroadcast(放送/配信)します。具体的には放送の内容と聞き手の情報を含んだオブジェクト(Intentオブジェクト)を引数にして、メソッドを呼び、AndroidOSに放送を委託します。

聞き手は、放送を受信する前に(OSに)登録されていなければなりません。聞き手には二種類あり、登録の方法で決まります。

登録する方法として次の二つの方法があります。

 

(1)静的に登録する

AndroidManifest.xmlに登録します。他のコンポーネントをAndroidManifest.xmlに登録するのと同じ方法です。ここで登録した聞き手は、BroadcastReceiverコンポーネントと呼ばれます。

(2)動的に登録する

実行時にプログラムの中で、動的に、聞き手を登録します。いったん登録してしまえば、静的に登録したコンポーネントと同じように使えます。

 

どの放送を実際に受け入れるか(受信するか)は、放送のときに、(引数として)付けられた、IntentオブジェクトとBroadcastReceiverに付けられたIntentFilterを比較して行われます。ActivityやServiceコンポーネントをバインドするのと同じ手法です。

 

静的に登録する場合はAndroidManifest.xmlの中に、intent-filterタグを使って、IntentFilterを記述します。

動的に登録する場合は、IntentFilterを生成し、それにパラメータを設定して、BroadcastReceiverオブジェクトと共に登録します。

動的に登録したBroadcastReceiverは、不要になったら抹消しなければなりません。Activityの場合はonResume()メソッドで登録して、onPause()メソッドで抹消するのがお薦めです。

 

イベントを処理するためによく使われる設計パターンObserverパターンの考え方は、イベントを起こす側(Observable)とそれを監視している側(Observer)が、互いにオブジェクトの参照(リファレンス)を保持しています(*1)。これは「固い」結合をしているといえます。

それに対して、BroadcastReceiverを使う方法は、そもそも参照を使って結合できないコンポーネント間の結合ができる仕掛けになっています。特に静的な登録で済む場合は、他の既存のアプリの放送(broadcast)をそのアプリのソースコードを変更しないで受信できます。これは、コンポーネント構造で作られているアプリの特長です。

注*1 Androidのアプリ間でObserverパターンを実装する場合は、Observable/Observerオブジェクトの本当の参照を相互に持つわけではありませんが、その利用者(開発者)には、見かけ上Observable/Observerの参照を持っているように見えています。

 

具体的に放送するのに使うメソッドの種類は次の通りです。

(1)非同期の放送

通常使われる放送です。これは非同期の放送です。ここで非同期というのは、各受信者が受信する順序は決まっていないという意味です。多くの場合、受信者は同時に受信します。これは、次の述べる同期した方法より効率的です。しかし、受信者は、その結果を戻すことが出来ませんし、途中で放送(の配信)を停止することも出来ません。

この放送を行う代表的なメソッドはContext.sendBroadcast()メソッドです。

(2)同期した放送

同期した放送(順序付けられた放送)が配信されます。同時には一つの受信者に配信されるだけです。各受信者は順番に受信しますので、結果を次々に伝えられます。もしくは、途中で中止して、それ以降の受信者には放送を伝えないようにも出来ます。受信の順序は、intent-filterのpriority属性で設定できます。同じ優先順位の受信者の順序は保証できません。

この放送を行う代表的なメソッドはContext.sendOrderedBroadcast()メソッドです。

 

ただし、状況によっては、非同期の放送の場合も、同期した放送と同じように、同時には一つの受信者にしか配信しないことがあります。特に、配信するために新しいプロセスを生成しなければならない場合はそうです。新しいプロセスを作るために負荷が高くなるのを防ぐためです。ただ、この場合も非同期の性格は保持されます。つまり、結果は戻せませんし、放送を中断することも出来ません。

 

BroadcastReceiverオブジェクトの基本クラスはBroadcastReceiverクラス(android.contentパッケージ)です。

静的に登録する場合は、<register>タグで、AndroidManifest.xmlに宣言します。動的に登録す場合は、Context.registerReceiver()メソッドを使います。

注Activity.onResume()でBroadcastReceiverオブジェクトを登録した場合は、Activity.onPause()で登録を抹消すべきです。そうすると余分なオーバヘッドを減らせます。登録の抹消を、Activity.onSaveInstanceState()メソッドの中ではしないようにしてください。この中で登録を抹消すると、元のActivityに戻っても、 BroadcastReceiverオブジェクトは復帰しません。

 

BroadcastReceiverが実装しなければならないメソッドはonReceive ()だけです。

BroadcastReceiverコンポーネントはonReceive()メソッドの実行中だけ有効です。いったん、そこから戻ると、Androidは、このコンポーネントは作業を完了し、非活性状態だと見なします。

このことは、onReceive()メソッドの中で処理できることに対して大きな影響があります。非同期でしなければいけない処理はonReceive()メソッドの中ではできません。というのは、非同期な操作を扱うには、onReceive()メソッドから戻らなければなりません。が、戻ると、その時点でBroadcastReceiverは活性でないとみなされ、非同期の操作が完了する前に、Andoroidは該当プロセスを停止する恐れがあります。

In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver. For the former, you should instead use the NotificationManager API. For the latter, you can use Context.startService() to send a command to the service.

特に、BroadcastReceiveの内からは、ダイログを表示したり、Serviceをバインドしたりできません。ダイログを表示するのであれば、通知(NotificationManagerのAPI)を使うべきです。Serviceに指示を送るために、(bindServise()メソッドで)バインドする代わりに、startService()メソッドを利用できます(*1)。また、既に起動されているServiceとバインドするにはpeekService(Context, Intent)メソッド(BroadcastReceiverクラスのメソッド)を使って下さい。

 

注*1 bindService()メソッドを呼ぶと、実際にバインドが実現すると、引数で設定したServiceConnectionオブジェクトのonServiceConnected()メソッドが(非同期に)呼び出されます。

Serviceの説明の中では、bindService()もstartService()も「バインド」という言葉を使って説明しました。startService()について、Serviceを起動して、Serviceと参照(リファレンス)を持ち合うというシナリオで説明してきました。その意味で、startService()も「バインド」するといえます。ただ、「Serviceと参照(リファレンス)を持ち合う」という部分は、必須ではありません。どちらかというと、それが不要な場面で使うのが本来のstartService()の目的のようです。web上には「バインド」を伴うstartService()メソッドの例が多数掲載されていますが、それは、設計思想には合わないようです(推測)。この注を念頭にBroadcastReceiverコンポーネントの非同期の処理に関する説明を読んで下さい。startService()を使った際にstaticなメソッドでServiceを関係付けるような処理を含む場合は、startService()もonReceive()メソッドの中で使えませんので注意して下さい。

 

代表的なメソッドについて説明します。説明しているメソッドにオーバロードされるメソッドがいくつかありますが、説明はしていません。詳細は原資料のマニュアル(リファレンス)を参照して下さい。

 

1.2 onReceive () メソッド(BroadcastReceiverクラス)

public abstract void onReceive (Context context, Intent intent)

引数

#

引数

説明

1

context

Context

2

intent

配信用メソッドの引数に設定されたIntent

 

放送のIntentがReceiverのIntentFilterを通過すると、このメソッドが呼ばれます。このメソッド内では、その時点の結果(値)を参照したり変更したりするのにBroadcastReceiverクラスのメソッドを利用できます。

onReceive()メソッドは通常は、主スレッドの中で呼ばれます。そのため、このメソッドの中で時間のかかる処理をしてはいけません。10秒を超えると中止又は停止するプロセスの候補になります。ポップアップダイアログも表示できません。

 

1.3 registerReceiver()メソッド(Contextクラス)

public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)

引数

#

引数

説明

1

receiver

登録するBroadcastReceiverオブジェクト

2

filter

受信すべき配信を選択するIntentFilter

 

戻り値  filterに合致したスティッキーなIntent。該当するIntentがない場合はnull。

スティッキーなIntentについては後ろの説明を参照して下さい。

 

BroadcastReceiverを動的に登録します。登録したオブジェクトはActivityの主スレッドで実行されます。

Androidは"スティッキー"(sticky *1)なIntentを配信できます。スティッキーなIntentは配信が終了した後も存在し続け、配信が終了した後に登録されたBroadcastReceiverにも配信されるIntentです。登録したBroadcastReceiverのIntentFilterがスティッキーなIntentに合致すれば、そのIntentが、このregisterReceiver()メソッドの戻り値として、あたかも、そのとき(メソッド呼び出し時)に配信されたかのように戻されます。

注*1 sticky:この場合はまとわり付くの意味が該当するように思います。

 

該当するスティッキーなIntentが複数個ある場合は、そのうちの一つだけ、メソッドの戻り値として戻し、残りは登録したBroadcastReceiverに配信されます。複数個あるうちのどれが戻り値で戻されるかは適宜決められます(アプリで知るすべはありません)。

もし、配信されたIntentがスティッキーであることが分かっていて、それを取り出すだけなら、receiver(第1引数)をnullにして、このメソッドを呼び出します。そうすれば、receiverは登録されないで、filter(第2引数)に合致Intentが戻されます。複数個ある場合は、上記と同じルール、つまり、戻されるIntentは適宜決定されます。

 

注:このメソッドはBroadcastReceiverコンポーネント(=AndroidManifest.xmlで宣言したBroadcastReceiver)から呼び出せません。しかし、実行時にこのメソッドを使って登録されたReceiverからはこのメソッドを呼び出せます。動的に登録したReceiverの生死は、登録したオブジェクトに結合しているからです。

 

1.4 unregisterReceiver ()メソッド(Contextクラス)

public abstract void unregisterReceiver (BroadcastReceiver receiver)

引数

#

引数

説明

1

receiver

登録を取り消すBroadcastReceiverオブジェクト

 

以前に動的に登録したReceiverの登録を取り消します。receiverに登録されたIntentFilterは削除されます。

 

1.5 sendBroadcast()メソッド(Contextクラス)

public abstract void sendBroadcast (Intent intent)

引数

#

引数

説明

intent

配信するIntent。受信者を決定するための情報と配信する情報を持ちます。

このIntentが通過するIntentFilterを持つReceiverだけが実際に受信します。

 

戻り値 なし。

与えられたIntentを待機しているReceiver(一つとは限らない)に配信します。この呼び出しは非同期です。つまり、Receiverが実行されている間に、この呼び出しの後続の処理も実行されます。Receiverの実行結果はReceiver間で伝わりません。また、配信を中止することもできません。Receiver間で結果を伝えたり、途中で配信を中断したい場合は、このメソッドではなくsendOrderedBroadcast(Intent, String)を使って配信しなければなりません。

 

1.6 sendOrderedBroadcast()メソッド(Contextクラス)

public abstract void sendOrderedBroadcast (

     Intent intent, String receiverPermission, BroadcastReceiver resultReceiver

    ,Handler scheduler, int initialCode, String initialData, Bundle initialExtras)

引数

#

引数

説明

intent

配信するIntent。受信者を決定するための情報と配信する情報を持ちます。このIntentが通過するIntentFilterを持つReceiverだけが実際に受信します。

receiverPermission

受信するのに必要なパーミッションの名前。パーミッションが不要の場合はnull

resultReceiver

配信の後の結果を受け取るためのBroadcastReceiver。最後に呼び出される。受信するReceiver群の最後のReceiverとして扱われます。

scheduler

resultReceiverのcallback(=onReceive())をスケジュールするためのHandler。Contextの主スレッドでいい場合はnull

initialCode

結果コードの初期値。多くの場合Activity.RESUL_OK

initialData

結果データの初期値。多くの場合null

initialExtras

結果のextrasの初期値。多くの場合null

 

Receiverから戻されるデータを受け取れる配信をするメソッドです。これは、Receiverから戻されるデータを受け取るための、別のBroadcastReceiverを引数として与えることによって実現します。このBroadcastReceiverは、一つの配信の最後のBroadcastReceiverとして扱われます。そのonReceive(Context,Intent)メソッドは、他のBroadcastReceiverから収拾した結果を付けて呼び出されます。配信の順序はpriorityで決まります(概説を参照)

sendBroadcast(Intent)と同じように、このメソッドは非同期(*1)です。resultReceiver.onReceive()が呼び出されるより前に戻ってくることが起こります。

注*1 同時には一つのReceiverだけが受信する受信(同期した受信)と、sendOrderedBroadcast()メソッドを呼び出した後、全Receiverが受信し終わるのを待たないで戻る(return)という非同期処理は別のことです。

参照  sendOrderedBroadcast(Intent intent, String receiverPermission)メソッド

 

実際に結果を伝達したり、取得するために次のメソッドを使います。原資料を参考にして下さい。

getResultCode()setResultCode(int code)

getResultData()setResultData(String data)

getResultExtras(boolean makeMap)setResultExtras(Bundle extras)

setResult(int code, String data, Bundle extras)

 

2.1Androidのサンプル

Androidのsdkといっしょに配布されているサンプルの中から紹介します。ファイルのパスの<android-sdk-windows>はAndroidのsdkが置かれているディレクトリを指します。

2.1.1 静的な登録

<android-sdk-windows>/samples/android-7/ApiDemos/AndroidManifest.xmlにreceiverの宣言の例があります。その一部を掲載します。全体は原資料を参照して下さい。

<?xml version="1.0" encoding="utf-8"?>

...

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.android.apis">

...

    <receiver android:name=".appwidget.ExampleAppWidgetProvider">

        ...

        <intent-filter>

            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

        </intent-filter>

    </receiver>

...

</manifest>

 

この例は、アクション名だけが指定されている例です。

 

2.1.2 動的な登録

<android-sdk-windows>/samples/android-7/Home/src

/com/example/android/home/Home.javaの例を掲載します。全体は原資料を参照して下さい。

登録だけでなくBroadcastReceiverクラスも内部クラスとして同じクラスに宣言されています。

 

... (104行)

private final BroadcastReceiver mWallpaperReceiver = new WallpaperIntentReceiver();

private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();

 

...(193行)

/**

 * Registers various intent receivers. The current implementation registers

 * only a wallpaper intent receiver to let other applications change the

 * wallpaper.

 */

private void registerIntentReceivers() {

    IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);

    registerReceiver(mWallpaperReceiver, filter);

 

    filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);

    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);

    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);

    filter.addDataScheme("package");

    registerReceiver(mApplicationsReceiver, filter);

}

 

...(594行)

/**

 * Receives notifications when applications are added/removed.

 */

private class ApplicationsIntentReceiver extends BroadcastReceiver {

    @Override

    public void onReceive(Context context, Intent intent) {

        ...

    }

}

 

2.1 LoggingReceiver

Androidのsdkのサンプルは内容が複雑ですので、構造が見えにくい嫌いがあります。実際的ではありませんが、構造が見えやい簡単な例を作ります。

ボタンを押すたびに、配信されて、受信側は送信されたメッセージををログする例を作ります。

静的な宣言をします。ソースコードの全体は付録を参照して下さい。

 

AndroidManifest.xml  一部

    <receiver android:name=".LoggingReceiver">

        <intent-filter>

            <action android:name="jp.co.ichi.receiver.LOG_ACTION" />

        </intent-filter>

    </receiver>

アクション名はjp.co.ichi.receiver.LOG_ACTIONとします。フィルタにはアクション名だけ記述することにします。

 

main.xml

<Button 

    android:id="@+id/button"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="click to broadcast"

    android:onClick="onClickToBroadcast"

    />

 

画面にボタンを配置するための記述です。android:onClick="onClickToBroadcast"を含めることで、このmain.xmlに対応するActivityの中では、Listenerを実装しないで、onClickToBroadcast()をonClick()メソッドの代わりにできます。

 

Activety  一部

    public void onClickToBroadcast(View button){

        Log.d(tag,"onClickToBroadcast starts.");

        Intent intent = new Intent("jp.co.ichi.receiver.LOG_ACTION");

        intent.putExtra("message","Test Broadcast:It's fine today.");

        sendBroadcast(intent);

    }

 

ボタンのクリックイベントの処理の中に、配信の処理を入れています。Intentには、アクション名だけ設定しています。

 

Receiver

public class LoggingReceiver extends BroadcastReceiver{

    private String tag = this.getClass().getSimpleName();

    @Override

    public void onReceive(Context context, Intent intent){

        // only to log

        String msg = intent.getStringExtra("message");

        Log.d(tag,"onReceive intent message=" + msg);

   }

}  

 

Receiverでは、受信したメッセージをログに表示しています。

 

2.2ToastingReceiver

ボタンを押すたびに、配信されて、受信側は送信されたメッセージをToastする例を作ります。

この例では動的な宣言をします。動的な例では受信クラスを内部クラスで実装されるのが普通ですが、この例では、分かりやすくするため独立したクラスとして実装しています。ソースコードの全体は付録を参照して下さい。

AndroidManifest.xmlにreceiverの宣言は不要です。

main.xmlはLoggingReceiverのmain.xmlと同じです。

 

Activity

    ...

    private BroadcastReceiver receiver;

    private static final String TOAST_ACTION = "jp.co.ichi.receiver.TOAST_ACTION";

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    }

    public void onResume() {

        super.onResume();

        receiver = new ToastingReceiver();

        IntentFilter filter = new IntentFilter();

        filter.addAction(TOAST_ACTION);

        registerReceiver(receiver, filter);

    }

    public void onPause() {

        super.onPause();

        unregisterReceiver(receiver);

        receiver = null;

    }

   

    public void onClickToBroadcast(View button){

        Log.d(tag,"onClickToBroadcast starts.");

        Intent intent = new Intent(TOAST_ACTION);

        intent.putExtra("message","Test Broadcast:It's fine today.");

        sendBroadcast(intent);

    }

    ...

 

onResume()メソッドで登録し、onPause()メソッドで登録を抹消しています。

onResume()メソッドとonPause()メソッドの両方でreceiverを使うので、receiverをフィールドに宣言しています。まt、onResume()メソッドとonClickToBroadcast ()メソッドの両方でアクション名を使うので、TOAST_ACTIONをフィールドに宣言しています。

 

ToastingReceiver

public class ToastingReceiver extends BroadcastReceiver{

    private String tag = this.getClass().getSimpleName();

    public void onReceive(Context context, Intent intent){

        // only to toast

        String msg = intent.getStringExtra("message");

        Toast.makeText(context

            , tag + " onReceive intent message=" + msg , Toast.LENGTH_LONG).show();

    }

}

 

Receiverでは、受信したメッセージをToastして表示しています。

 

2.3

同期した放送の例を試します。

LoggingReceiverクラスを変更して、途中結果の器(Bundleクラスに)に設定します。テストをするために、地中結果を書き出す処理も追加します。

    public void onReceive(Context context, Intent intent){

        // only to log

        String msg = intent.getStringExtra("message");

        Log.d(tag,"onReceive intent message=" + msg);

        Bundle extras = getResultExtras(true);

        extras.putString("key_" + tag, "TOKYO");

        printBundle(extras,"extras");

       

   }

    /*

     * utility method

     */

    private void printBundle(Bundle b, String title){

        Set<String> keys = b.keySet();

        Iterator<String> iter = keys.iterator();

        String key;

        while(iter.hasNext()){

            key = iter.next();

            Log.d(tag,"onReceive intent bundle key=" + key + " value=" + b.getString(key));

        }

    }

 

LoggingReceiverクラスと内容のクラスを作成し、名前はLoggingReceiver2とします。設定する途中結果は、LoggingReceiverとLoggingReceiver2で区別がつくように変更します。"TOKYO"を"OSAKA"に変更すれば十分です。

LoggingReceiverクラスと内容のクラスを作成し、名前はResultReceiverとします。ResultReceiverから、途中結果を設定している部分は削除します。

ActivityのonClickでsendBroadcast()メソッドの代わりに、sendOrderedBroadcast()メソッドを使います。

    public void onClickToBroadcast(View button){

        Log.d(tag,"onClickToBroadcast starts.");

        Intent intent = new Intent("jp.co.ichi.receiver.LOG_ACTION");

        intent.putExtra("message","Test Broadcast:It's fine today.");

        printMatchIntentFilter(intent);

        String receiverPermission = null;

        BroadcastReceiver resultReceiver = new ResultReceiver();

        Handler scheduler =null;

        int initialCode = Activity.RESULT_OK;

        String initialData = "InitialData ";

        Bundle initialExtras =new Bundle();

        initialExtras.putString("initialExtras_key","initialExtras_value");

        sendOrderedBroadcast (

             intent

            ,receiverPermission

            ,resultReceiver

            ,scheduler

            ,initialCode

            ,initialData

            ,initialExtras

            );

    }

 

最後にAndroidManifest.xmlにreceiverを登録します。LoggingReceiverとLoggingReceiver2のintent-filterにはpriorityを設定します。prioprityの値が大きいものの方が先に呼ばれます。どちらが先に呼ばれるか、値の大小を変えてテストしてみて下さい。

        <receiver android:name=".LoggingReceiver">

            <intent-filter android:priority="1">

                <action android:name="jp.co.ichi.receiver.LOG_ACTION" />

            </intent-filter>

        </receiver>

        <receiver android:name=".LoggingReceiver2">

            <intent-filter android:priority="2">

                <action android:name="jp.co.ichi.receiver.LOG_ACTION" />

            </intent-filter>

        </receiver>

 

付録

付録A LoggingReceiverソースコード

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.example.broadcast"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".HelloBroadcast3"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <receiver android:name=".LoggingReceiver">

            <intent-filter>

                <action android:name="jp.co.ichi.receiver.LOG_ACTION" />

            </intent-filter>

        </receiver>

    </application>

</manifest>

 

main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView 

    android:id="@+id/tv1"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/hello"

    />

<Button 

    android:id="@+id/button"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="click to broadcast"

    android:onClick="onClickToBroadcast"

    />

</LinearLayout>

 

Activety

public class HelloBroadcast3 extends Activity {

    private String tag = this.getClass().getSimpleName();

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    }

    public void onClickToBroadcast(View button){

        Log.d(tag,"onClickToBroadcast starts.");

        Intent intent = new Intent("jp.co.ichi.receiver.LOG_ACTION");

        intent.putExtra("message","Test Broadcast:It's fine today.");

        sendBroadcast(intent);

    }

}

 

Receiver

package com.example.broadcast;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.util.Log;

 

 

public class LoggingReceiver extends BroadcastReceiver{

    private String tag = this.getClass().getSimpleName();

    @Override

    public void onReceive(Context context, Intent intent){

        // only to log

        String msg = intent.getStringExtra("message");

        Log.d(tag,"onReceive intent message=" + msg);

   }

}  

 

付録B ToastingReceiverのソースコード

AndroidManifest.xml

EclipseでAndroidプロジェクトを作成したときに自動生成されるAndroidManifest.xmlをそのまま使います。

 

main.xml

LoggingReceiverのmain.xmlと同じです。

 

Activety

public class HelloBroadcast4 extends Activity {

    private String tag = this.getClass().getSimpleName();

    private BroadcastReceiver receiver;

    private static final String TOAST_ACTION = "jp.co.ichi.receiver.TOAST_ACTION";

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    }

    public void onResume() {

        super.onResume();

        receiver = new ToastingReceiver();

        IntentFilter filter = new IntentFilter();

        filter.addAction(TOAST_ACTION);

        registerReceiver(receiver, filter);

    }

    public void onPause() {

        super.onPause();

        unregisterReceiver(receiver);

        receiver = null;

    }

   

    public void onClickToBroadcast(View button){

        Log.d(tag,"onClickToBroadcast starts.");

        Intent intent = new Intent(TOAST_ACTION);

        intent.putExtra("message","Test Broadcast:It's fine today.");

        sendBroadcast(intent);

    }

}

 

Receiver

public class ToastingReceiver extends BroadcastReceiver{

    private String tag = this.getClass().getSimpleName();

    public void onReceive(Context context, Intent intent){

        // only to toast

        String msg = intent.getStringExtra("message");

        Toast.makeText(context

            , tag + " onReceive intent message=" + msg , Toast.LENGTH_LONG).show();

    }

}

 

付録C 同期した放送のソースコード

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.example.broadcast"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".HelloBroadcast5"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <receiver android:name=".LoggingReceiver">

            <intent-filter android:priority="1">

                <action android:name="jp.co.ichi.receiver.LOG_ACTION" />

            </intent-filter>

        </receiver>

        <receiver android:name=".LoggingReceiver2">

            <intent-filter android:priority="2">

                <action android:name="jp.co.ichi.receiver.LOG_ACTION" />

            </intent-filter>

        </receiver>

    </application>

</manifest>

 

main.xml

LoggingReceiverのmain.xmlと同じです。

 

Activety

public class HelloBroadcast5 extends Activity {

    private String tag = this.getClass().getSimpleName();

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    }

    public void onClickToBroadcast(View button){

        Log.d(tag,"onClickToBroadcast starts.");

        Intent intent = new Intent("jp.co.ichi.receiver.LOG_ACTION");

        intent.putExtra("message","Test Broadcast:It's fine today.");

        String receiverPermission = null;

        BroadcastReceiver resultReceiver = new ResultReceiver();

        Handler scheduler =null;

        int initialCode = Activity.RESULT_OK;

        String initialData = "InitialData ";

        Bundle initialExtras =new Bundle();

        initialExtras.putString("initialExtras_key","initialExtras_value");

        sendOrderedBroadcast (

             intent

            ,receiverPermission

            ,resultReceiver

            ,scheduler

            ,initialCode

            ,initialData

            ,initialExtras

            );

    }

 

Receiver

public class LoggingReceiver extends BroadcastReceiver{

    private String tag = this.getClass().getSimpleName();

    @Override

    public void onReceive(Context context, Intent intent){

        // only to log

        String msg = intent.getStringExtra("message");

        Log.d(tag,"onReceive intent message=" + msg);

        Bundle extras = getResultExtras(true);

        extras.putString("key_" + tag, "TOKYO");

        printBundle(extras,"extras");

       

   }

    /*

     * utility method

     */

    private void printBundle(Bundle b, String title){

        Set<String> keys = b.keySet();

        Iterator<String> iter = keys.iterator();

        String key;

        while(iter.hasNext()){

            key = iter.next();

            Log.d(tag,"onReceive intent bundle key=" + key + " value=" + b.getString(key));

        }

    }

}  

 

もう一つのReceiver、LoggingReceiver2はLoggingReceiverの"TOKYO"を"OSAKA"に変えます。

 

結果のReceiver

public class ResultReceiver extends BroadcastReceiver{

    private String tag = this.getClass().getSimpleName();

    @Override

    public void onReceive(Context context, Intent intent){

        // only to log

        String msg = intent.getStringExtra("message");

        Log.d(tag,"onReceive intent message=" + msg);

        Bundle extras = getResultExtras(true);

        printBundle(extras,"extras");

   }

    /*

     * utility method

     */

    private void printBundle(Bundle b, String title){

        Set<String> keys = b.keySet();

        Iterator<String> iter = keys.iterator();

        String key;

        while(iter.hasNext()){

            key = iter.next();

            Log.d(tag,"onReceive intent bundle key=" + key + " value=" + b.getString(key));

        }

    }

}  

 

 

 

付録 IntentReceiver

かっては、BroadcastReceiverはIntentReceiverと呼ばれていたようです。web上の旧い記事にIntentReceiverが出てくることがあります。

資料

http://davanum.wordpress.com/2007/12/15/android-listen-for-incoming-sms-messages/

the class IntentReceiver does no longer exists in the SDK 1.1 and is renamed to BroadcastReceiver.  SDK1.1にはIntentReceiverはありません。IntentReceiverはBroadcastReceiverに名前を変えました。

 

付録E 資料

http://www.slideshare.net/CodeAndroid/android-intent-intent-filter-broadcast-receivers

Android: Intent, Intent Filter, Broadcast Receivers

 

以上