Androidの基本-BroadcastReceiverの包括的な分析

前書き

  • 同じくAndroidの4つの主要コンポーネントの1つであるBroadcastReceiverには、ブロードキャストパブリッシャーとブロードキャストレシーバーという2つの重要な役割があります。

使用シナリオと機能

効果

  • これは、アプリケーションによって送信されたブロードキャストを受信または監視し、それに応じて応答するために使用されます。

使用するシーン

  • アプリケーション内および異なるアプリケーション間の対話型通信を含む、異なるコンポーネント間の通信に使用されます。
  • ネットワークの変更、SDカードのステータスなどのシステムリソースの変更を監視します。
  • マルチプロセス通信

実現原理

これは、メッセージ発行者/メッセージサブスクライバーモデルに基づく、典型的なオブザーバーパターンのアプリケーションです。

ここに写真の説明を書いてください

原理の説明

  1. メッセージサブスクライバー(ブロードキャストレシーバー)は、バインダーメカニズムを介してメッセージセンターAMSに登録します
  2. メッセージ発行者(ブロードキャスト発行者)は、バインダーメカニズムを介してメッセージセンターAMSにブロードキャストを送信します
  3. 放送局の要件に応じて、AMSは登録リストで一致する加入者を検索します。一致する加入者が見つかると、メッセージセンターAMSは対応する放送を加入者に送信します。
    1. メッセージセンターのAMS検索の基本は、インテントフィルター(IntentFilter)とパーミッション(permission)です。
  4. 最後に、メッセージサブスクライバー(ブロードキャストレシーバー)がブロードキャストを受信した後、onReceiverメソッドがコールバックされます。

1.ブロードキャストパブリッシャー:sendBroadcast、sendOrderedBroadcast
2.ブロードキャストレシーバー:BroadcastReceiver

特定の用途

  • BroadcastReceiverクラスを継承し、onReceiverメソッドをオーバーライドします。ブロードキャストが受信されると、メソッドをアクティブにコールバックします。
  • 放送受信機を登録する

放送受信機を登録するには、静的登録と動的登録の2つの方法があります。

静的登録:

AndroidMainfestファイルで宣言するだけで、属性は次のようになります。

<receiver
    android:enabled=["true" | "false"]
    //此broadcastReceiver能否接收其他App的发出的广播
    //默认值是由receiver中有无intent-filter决定的:如果有intent-filter,默认值为true,否则为false
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
    //继承BroadcastReceiver子类的类名
    android:name=".mBroadcastReceiver"
    //具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收;
    android:permission="string"
    //BroadcastReceiver运行所处的进程
    //默认为app的进程,可以指定独立的进程
    //注:Android四大基本组件都可以通过此属性指定自己的独立进程
    android:process="string" >

    //用于指定此广播接收器将接收的广播类型
    //本示例中给出的是用于接收网络状态改变时发出的广播
    <intent-filter>
          <action android:name="android.net.conn.CONNETIVITY_CHANGE"/>
    </intent-filter >
</receiver>

静的登録、BroadcastReceiverクラスは、アプリが初めて起動されたときにインスタンス化され、ブロードキャストレシーバーもAMSに登録されます。つまり、アプリの起動時にonReceiverメソッドがコールバックされます。
ブロードキャストの優先度を上げるには、インテントフィルターで属性の優先度を設定します。値が大きいほど、優先度が高くなります。

<receiver android:name=".MyBroadcastReceiver">
    <intent-filter android:priority="100">        
     </intent-filter>
</receiver>

動的登録:

コンテンツのregisterReceiverメソッドを使用して登録します

 public abstract Intent registerReceiver(BroadcastReceiver receiver,
            IntentFilter filter, @Nullable String broadcastPermission,
            @Nullable Handler scheduler, @RegisterReceiverFlags int flags);

上記は、registerReceiverメソッドの最も多くのパラメーターの1つです。レシーバーとフィルターを渡す必要があり、その他はオプションです。

  • 受信機:受信した放送、つまり放送受信機を処理するために使用されます
  • filter:インテントフィルター。ブロードキャストの優先度を設定し、ブロードキャストのタイプを受け入れることができます。
  • BroadcastPermission:ブロードキャスト許可を設定します。つまり、送信されるブロードキャストインテント(Intent)には同じ文字列が含まれている必要があります。オプション
  • スケジューラー:ブロードキャストレシーバーがメッセージの処理を受け入れるスレッドを設定します(onReceiver)、オプション、デフォルトはメインスレッドです
  • フラグ:いくつかの追加のフラグオプション、オプション
//注册广播
 mReceiver = new MyBroadcastReceiver();
 IntentFilter filter = new IntentFilter();
 //必须action的匹配规则,否则无法接收到消息,在发送广播的意图中必须匹配action的字符串
 filter.addAction("test");
 registerReceiver(mReceiver,filter);

//发送广播
Intent intent = new Intent();
intent.setAction("test");
 sendBroadcast(intent);

登録があると、必然的に登録が解除されます。通常、onDestroyまたはonPauseで登録を解除します。登録を解除しないと、メモリリークが発生します。

 @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mReceiver);
    }

動的登録中は、新しいMyBroadcastReceiver()オブジェクトを繰り返し登録できないことに注意してください。そうしないと、onReceiverメソッドが複数回コールバックされ、いくつかの追加の問題が発生します。

2つの登録方法の違い

ここに写真の説明を書いてください

放送分類

  • 通常放送
  • システム放送
  • 注文放送
  • スティッキーブロードキャスト
  • アプリ内のローカルブロードキャスト

通常放送

1.ホームページ(BroadcastReceiver)で放送受信機を登録します。動的登録方式の場合、マッチングフィールドアクションを設定する必要があります。そうしないと、放送を受信できません。

mReceiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("test");
registerReceiver(mReceiver,filter);

//或者

<receiver android:name=".MyBroadcastReceiver">
   <intent-filter>
     <action android:name="test"/>
    </intent-filter>
</receiver>

2.インテントインテンションを介してブロードキャストを送信するには、インテンションに同じアクション文字列(登録されたものと同じ)を追加する必要があります。そうしないと、ブロードキャストを受信できません。

 Intent intent = new Intent();
 intent.setAction("test");
 sendBroadcast(intent);

3.ブロードキャストを受信した後、BroadcastReceiverのonReceiveメソッドをアクティブにコールバックします。

public class MyBroadcastReceiver extends BroadcastReceiver{
    
    

    private static final String TAG = "BroadcastReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive: "+intent.getAction());

    }
}

システム放送

Androidシステムには多くのシステムブロードキャストが組み込まれています。システムステータス情報が変更されると、電源オン、バッテリーの変更、ネットワークの変更など、対応するブロードキャストが送信されます。登録と登録にも同じアクションが必要であることがわかっています。ブロードキャストの送信、およびシステムブロードキャストさまざまなアクションもあります。Androidシステムは、次のようにアクションをブロードキャストします。

ここに写真の説明を書いてください

<receiver android:name=".MyBroadcastReceiver">
            <intent-filter>
                <!-- 应用添加 -->
                <action android:name="android.intent.action.PACKAGE_ADDED"/>
                <!-- 应用删除 -->
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <!-- 应用替换 -->
                <action android:name="android.intent.action.PACKAGE_REPLACED"/>
                <!-- 应用重新启动 -->
                <action android:name="android.intent.action.PACKAGE_RESTARTED"/>

                <!--必须设置scheme,相当于URI,不然收不到系统广播-->
                <data android:scheme="package"/>
            </intent-filter>
        </receiver>

システムブロードキャストを使用する場合は、ブロードキャストレシーバーの登録時に関連するアクションを定義するだけで、手動でブロードキャストを送信する必要はありません。システムに関連する操作がある場合、システムブロードキャストは自動的に実行されます。

以下を動的に登録することもできます。

 mReceiver = new MyBroadcastReceiver();
 IntentFilter filter = new IntentFilter();
 filter.addAction("android.intent.action.PACKAGE_REMOVED");
 filter.addAction("android.intent.action.PACKAGE_ADDED");
 filter.addDataScheme("package");
 registerReceiver(mReceiver,filter);

注文放送

同じブロードキャストがブロードキャストレシーバーによって同時に受信された後、ブロードキャストが配信され続ける前に、現在のブロードキャストレシーバーのサービスロジックを実行する必要があります。順番に受信され、受信ルールは次のとおりです。

  1. デフォルトでは、同じ登録方法で、登録順に受信されます
  2. 優先度属性値で最大から最小に並べ替える
  3. Priority属性値が同じ場合、動的に登録されたブロードキャストが優先されます。

放送が中断された場合、次の放送受信機は放送を受信できなくなります

例:

1.放送受信機

public class MyBroadcastReceiver extends BroadcastReceiver{
    
    

    private static final String TAG = "BroadcastReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive: "+intent.getAction());

        for (int i = 0; i < 5; i++) {
            Log.e(TAG, "onReceive: "+i);
        }
    }
}

public class MyBroadcastReceiver2 extends BroadcastReceiver{
    
    

    private static final String TAG = "BroadcastReceiver2";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive2: "+intent.getAction());

    }
}

放送登録

        //注册广播
        <receiver android:name=".MyBroadcastReceiver">
            <intent-filter android:priority="100">
                <action android:name="test"/>
            </intent-filter>
        </receiver>
        //注册广播2
        <receiver
            android:name=".MyBroadcastReceiver2">
            <intent-filter android:priority="80">
                <action android:name="test"/>
            </intent-filter>
        </receiver>

     //或者
     mReceiver = new MyBroadcastReceiver();
     mReceiver2 = new MyBroadcastReceiver2();
     IntentFilter filter = new IntentFilter();
     filter.addAction("test");
     filter.setPriority(100);
     registerReceiver(mReceiver,filter);
     filter.setPriority(80);
     registerReceiver(mReceiver2,filter);

ブロードキャストを送信する

Intent intent = new Intent();
intent.setAction("test");
sendOrderedBroadcast(intent,null);

出力結果:
ここに写真の説明を書いてください

順序付きブロードキャストの使用プロセスは通常のブロードキャストと非常に似ています。唯一の違いは、ブロードキャストの送信方法が異なることです。sendOrderedBroadcastは、順序付きブロードキャストかどうかを判断するために、onReceiveでisOrderedBroadcastメソッドを呼び出すことができます。trueは次のとおりです。ブロードキャスト配信を中断する必要がある場合は、onReceiveでabortBroadcastメソッドを呼び出すことができます。

アプリ内のローカルブロードキャスト

Androidでは、ブロードキャストはデフォルトでアプリ間で直接通信できます(クロスプロセス)。エクスポートされた属性は
デフォルトでtrueであるため、ブロードキャストはデフォルトでクロスプロセスであり、ブロードキャストは送信インテントインテントとインテントフィルターインテントフィルターの一致する判断に基づいて、BroadcastReceiverのonReceiverメソッドがコールバックされるかどうかを決定します。次の問題が発生する可能性があります。

  • 他のアプリから送信されたブロードキャストインテントが現在のアプリのインテントフィルターと一致する場合、現在のアプリは引き続きブロードキャストを受信して​​処理します。犯罪者がアプリのインテントフィルターを知っている場合、この脆弱性を介していくつかの悪い情報をプッシュする可能性があり、アプリのセキュリティに影響を与えます。

上記の問題を考慮して、次の解決策があります。

  1. グローバルブロードキャストをローカルブロードキャストに設定する
    1. ブロードキャスト登録エクスポートプロパティがfalseに設定されているため、現在のアプリ内部の未送信のブロードキャストが
      受信さない場合
    2. ブロードキャストを送受信するときは、アクセス許可の検証に対応するアクセス許可を追加します。
    <receiver android:name=".MyBroadcastReceiver"
            android:exported="false">
            <intent-filter android:priority="100">
                <action android:name="test"/>
            </intent-filter>
        </receiver>
<!--1、自定义新权限-->
 <!--自定义新权限-->
    <permission android:name="com.hzw.MY_RECEIVER"/>

    <application
        ……
        <!-- 2、发送方必须要拥有com.hzw.permission.MY_RECEIVER权限,接受器才会接受-->
        <receiver android:name=".MyBroadcastReceiver"
            android:permission="com.hzw.permission.MY_RECEIVER">
            <intent-filter android:priority="100">
                <action android:name="test"/>
            </intent-filter>
        </receiver>

       ……
    </application>

2.システムによってカプセル化されたLocalBroadcastManagerクラスであるローカルブロードキャストを使用します

mReceiver2 = new MyBroadcastReceiver2();
IntentFilter filter = new IntentFilter();
filter.addAction("test");
//获取LocalBroadcastManager类的实例,通过该实例注册广播             
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.registerReceiver(mReceiver2,filter);

//注销也需通过LocalBroadcastManager进行注销
mLocalBroadcastManager.unregisterReceiver(mReceiver2);

LocalBroadcastManagerによって送信されるアプリ内ブロードキャストの場合、静的にではなく、LocalBroadcastManagerを介してのみ動的に登録できます。

感謝

https://blog.csdn.net/carson_ho/article/details/52973504
https://blog.csdn.net/javensun/article/details/7334230
http://h529820165.iteye.com/blog/1656778

おすすめ

転載: blog.csdn.net/hzw2017/article/details/80959378