Android四大元件之BroadcastReceiver

StarkSong發表於2019-03-08

BroadcastReceiver:

  1. Android四大元件之一,通過intent傳送接收訊息。系統本身也會傳送廣播,比如網路發生變化,螢幕的熄滅和亮起,接收簡訊,開機等這些行為都會傳送廣播。我們可以通過特定的、系統約定好的Action進行接收廣播,來處理一些我們自己的邏輯。不過監聽系統廣播,大多是需要進行許可權申請的。
  2. 分為有序廣播無序廣播本地廣播

BroadcastReceiver的使用:

基本用法

繼承 BroadcastReceiver 類,重寫 onReceive 方法。

public class MyBroadcastReceiver1 extends BroadcastReceiver {
    private static final String TAG = "廣播接收者===";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive: 我是動態註冊的廣播111111111111    "+hashCode());
    }
}
複製程式碼

註冊廣播

  1. 靜態註冊

    在 AndroidManifest.xml 裡面進行註冊

    <!--在設定action裡面的name的時候,雖然可以隨便設定,但是儘量用包名做
    字首,符合程式規則,這裡為了測試就隨便寫了-->
    <receiver
        android:name=".broadcastreceiver.MyBroadcastReceiver3">
        <intent-filter android:priority="1010">
            <action android:name="test" />
        </intent-filter>
    </receiver>
    複製程式碼
  2. 動態註冊

    首先建立例項

    MyBroadcastReceiver1  myBroadcastReceiver1 = new MyBroadcastReceiver1();
    複製程式碼

    註冊廣播

    IntentFilter filter1 = new IntentFilter("test");
    //設定優先順序
    filter1.setPriority(100);
    registerReceiver(myBroadcastReceiver1, filter1);
    複製程式碼

    反註冊廣播

    unregisterReceiver(myBroadcastReceiver1);
    複製程式碼

    注意: 1. 一般我們在進行動態註冊後,一定要進行反註冊操作,避免資源浪費。反註冊操作一般在 Activity 的 onDestroy 中進行 2.一定要在進行註冊後才進行反註冊操作,否則程式會直接崩潰。

傳送廣播

  • 有序廣播

    Intent test = new Intent("test");
    sendOrderedBroadcast(test,null);
    //or 下面方法為指定一個 最終廣播接收者 此繫結著不受 中斷廣播影響,最終都會接收到廣播。
    /*有意思的是,如果最終廣播接受者的接收訊息的優先順序在執行中斷廣播操作的廣播接受者之上的時候,
    會先接收到訊息,然後中斷廣播後最終又會接收到一次訊息,總共接收到兩次訊息。
    當然,如果不執行中斷廣播的操作,還是會先按照廣播接收順序接收一次訊息後,最終再接收一次,總共兩次*/
    sendOrderedBroadcast(test, null, myBroadcastReceiver1, null, 0, null, null);
    複製程式碼
    • 可以通過abortBroadcast()進行中斷廣播,後面的廣播接受者都不能進行接收廣播。

    • 可以通過在 onReceive 改變傳遞資料。

      
      @Override
      public void onReceive(Context context, Intent intent) {
          Bundle bundle = new Bundle();
           //傳遞資料
          bundle.putString("aaa","我是接受者1");
          setResultExtras(bundle);
      }
      ///////////////////////////////
      @Override
      public void onReceive(Context context, Intent intent) {
          Bundle resultExtras = getResultExtras(true);
          //要對resultExtras 進行判空處理,如果前面沒有傳遞資料,這裡的resultExtras會為null
          //改變前面廣播傳送的資料
          if(resultExtras!=null){
               resultExtras.putString("aaa","我是接受者2");
          }
      }
      //最終後面接收到的 "aaa" 的值為 "我是接受者2"
      ///////////////////
      @Override
      public void onReceive(Context context, Intent intent) {
          //中斷廣播
          abortBroadcast();
      }
      複製程式碼
    • sendOrderedBroadcast(test,null) 第二個引數是廣播接受者指定所需的許可權。 (這個有待研究, 在設定指定許可權後,好像其他沒有指定許可權的廣播接收者也能收到廣播,懵逼。。。看到網上的提示:Android對同一PID的許可權驗證是直接通過的。因此如果Sender和Receiver在同一程式,是不能做許可權限制的。 具體程式碼可以看一下ActivityManagerService的checkComponentPermission)

  • 無序廣播

    Intent intent2 = new Intent("test");
    sendBroadcast(intent2);
    複製程式碼
    • 無法中斷廣播。
    • 無序廣播雖說官方文件上說是,接收訊息的順序是無序的,但是通過測試,還是有順序的。
  • 本地廣播

    使用 LocalBroadcastManager 進行傳送本地廣播和註冊本地廣播,只能傳送無序廣播。本地廣播只能進行動態註冊,其傳送的廣播只能在本程式中接收,註冊的廣播只能被本程式傳送的廣播接收。

    //獲取本地廣播管理器單例
    LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
    //註冊本地廣播
    IntentFilter filter1 = new IntentFilter("test");
    filter1.setPriority(100);
    localBroadcastManager.registerReceiver(myBroadcastReceiver1, filter1);
    //傳送本地廣播
    Intent test = new Intent("test");
    localBroadcastManager.sendBroadcast(test);
    複製程式碼

    使用本地廣播可以防止外部應用惡意接收我們的廣播資料,並進行篡改。也可以防止外部應用惡意的傳送垃圾廣播給我們。

廣播接收順序

- 有序廣播:
    1. 優先順序(priority)高的優先於低的。
    2. 同優先順序不同註冊方式情況下,動態高於靜態。
    3. 同優先順序同註冊方式情況下,動態註冊:先註冊的高於後註冊的,靜態註冊:先掃描的優先於後掃描的。
- 無序廣播:
    1. 動態註冊高於靜態註冊,無視優先順序。
    2. 不同優先順序同註冊方式,根據優先順序高低進行排序。
    3. 同優先順序同註冊方式情況下,動態註冊:先註冊的高於後註冊的,靜態註冊:先掃描的優先於後掃描的。
複製程式碼

廣播特點

  1. 廣播接受者每次接收廣播時,都會重新建立一個例項(可以通過列印其hashcode值進行驗證)
  2. 優先順序欄位 priority 取值範圍為 -1000-1000。(測試發現其實可以最大取到Integer.MAX_VAUE,就是2的31次方,2147483648)
  3. onReceive裡不能進行耗時操作,因為廣播接受者依賴於主執行緒,執行過久(網上看到說是10s)會報ANR(Application Not Response),也不建議在onReceive裡面建立一個子執行緒進行耗時操作,因為在onReceive裡面的業務邏輯執行完後,就有可能被系統回收,子執行緒依賴的活動元件被回收後,子執行緒任務有可能還沒結束,此時會被標記為空程式,在記憶體吃緊的時候會被優先殺死回收。我們可以在Activity或者Service裡面進行一些耗時操作。

Android8.0靜態註冊廣播接收不到隱式傳送的廣播

在Android8.0以上,靜態註冊的廣播,是接收不到隱式傳送的廣播的,只能接收通過顯示方式傳送的廣播,也就是 intent.setComponent() 指定一個廣播。 動態註冊的廣播不受影響。

Intent intent2 = new Intent("test");
intent2.setComponent(new ComponentName(this, MyBroadcastReceiver4.class));
sendBroadcast(intent2);
複製程式碼

參考文獻:

《愛上Android》書籍

Android 四大元件

相關文章