1. 程式人生 > >Android查缺補漏--BroadcastReceiver的類型與使用

Android查缺補漏--BroadcastReceiver的類型與使用

cep 上一個 int reat androi 無需 receive 一起學 text

Broadcast 是一種被用於應用內和應用之間傳遞信息的機制。一個廣播可以對應多個接受者。一個完整的廣播機制,需要具有以下三個要素:

  • 發送廣播的Broadcast
  • 接受廣播的BroadcastReceiver
  • 傳遞信息的Intent

廣播的註冊分為靜態註冊和動態註冊:

  • 靜態註冊:靜態註冊的廣播是指在AndroidManifest中註冊的廣播,此種廣播在應用安裝時就被系統解析,不需要啟動應用就可以收到相應的廣播。
<receiver android:name=".broadcast.MyBroadcastReceiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>
  • 動態註冊:通過Context.registerReceiver()來實現,不需要時要通過Context.unRegisterReceiver()解除廣播,此種廣播必須應用啟動後才能註冊並接收廣播。

    // 動態註冊廣播接收器
    registerReceiver(new DynamicBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));

廣播又分為普通廣播、有序廣播、本地廣播和sticky廣播。

一、普通廣播

普通廣播通過Context.sendBroadcast()發送,我們沒有辦法制定Receiver們對於普通廣播的接收順序。理論上所有的接收器(Receiver)接收到廣播的順序不確定,但一般是按照其在AndroidMainfest.xml文件中註冊的順序(不絕對)。
普通廣播中,接受者不能將處理結果傳遞給下一個接收器,也無法終止廣播的傳播。

如下代碼是一個靜態註冊的廣播示例:

public class MyBroadcastReceiver extends BroadcastReceiver {

    String TAG = MyBroadcastReceiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
    }
}

然後再AndroidMainfest.xml中註冊這個廣播:

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

接下來在Activity中調用Context.sendBroadcast()發送廣播就可以了:

Intent intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一個普通廣播");
sendBroadcast(intent);

log如下:

12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個普通廣播
  • 普通廣播的接收順序測試
    我們仿照MyBroadcastReciver創建多個接收器,代碼一樣:
/**
 * 靜態註冊的廣播接收器2
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast2Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast2Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
    }
}
/**
 * 靜態註冊的廣播接收器3
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast3Receiver extends BroadcastReceiver {...}
/**
 * 靜態註冊的廣播接收器4
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast4Receiver extends BroadcastReceiver {...}
/**
 * 靜態註冊的廣播接收器5
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast5Receiver extends BroadcastReceiver {...}
/**
 * 靜態註冊的廣播接收器6
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast6Receiver extends BroadcastReceiver {...}

然後在AndroidMainfest.xml中為以上廣播都註冊同一個action

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

<receiver android:name=".broadcast.MyBroadcast6Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast2Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast3Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast4Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast5Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

點擊發送廣播,查看log:

12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.268 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.271 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.273 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.277 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到廣播消息:我是一個普通廣播
12-08 17:29:44.280 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到廣播消息:我是一個普通廣播

二、有序廣播

在AndroidMainfest.xml中註冊廣播時通過priority(值越優先級越高)節點為廣播添加優先級,然後再用Context.sendOrderedBroadcast()發送,接收者們就會按照優先級順序依次執行。

有序廣播的接收者和給下一個接收者傳遞數據,並且接收者在收到廣播之後可以拋棄廣播,使廣播不再向後傳遞。

為上面6個接收器添加優先級:

<receiver android:name=".broadcast.MyBroadcastReceiver">
    <intent-filter android:priority="1">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast6Receiver">
    <intent-filter android:priority="6">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast2Receiver">
    <intent-filter android:priority="2">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast3Receiver">
    <intent-filter android:priority="3">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast4Receiver">
    <intent-filter android:priority="4">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast5Receiver">
    <intent-filter android:priority="5">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

然後通過sendOrderedBroadcast發送廣播觀察log:

intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一個有序廣播");
sendOrderedBroadcast(intent, null);

log如下:

12-08 18:17:26.455 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.462 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.464 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.465 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.466 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:17:26.467 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個有序廣播
  • abortBroadcast()拋棄廣播:
    普通的廣播是沒有辦法拋棄的,否則會拋出RuntimeException的異常。

只有有序廣播才可以通過此方法拋棄。我們在MyBroadcast6Receiver中添加abortBroadcast()方法:

public class MyBroadcast6Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast6Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
        abortBroadcast();
        Log.i(TAG, "丟棄廣播");
    }
}

然後點擊發送有序廣播,log如下:

12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 丟棄廣播

可以看到廣播已經被丟棄了。

  • setResult()傳遞給下一個接收者結果。
  • getResult()接收上一個接收者的結果。

在MyBroadcast6Receiver中添加setResult方法,在MyBroadcast5Receiver添加getResult方法:

public class MyBroadcast6Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast6Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
//        abortBroadcast();
//        Log.i(TAG, "丟棄廣播");
        setResult(006, "我是老6傳來的消息", null);
    }
}
public class MyBroadcast5Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast5Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到廣播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
        String data = getResultData();
        Log.i(TAG, "data=" + data);
    }
}

log如下:

12-08 18:40:01.415 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: data=我是老6傳來的消息
12-08 18:40:01.440 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.442 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.445 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個有序廣播
12-08 18:40:01.447 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個有序廣播

三、本地廣播

以上的廣播對於系統來說是全局的,發出廣播後,系統內的應用只要註冊了相應的接收器就都可以收到廣播。如果我們想在本應用發出的廣播只在此應用內可以收到,那麽可以使用本地廣播了。

本地廣播由 LocalBroadcastManager 管理,是在 API 21 以後添加的,使用起來也很方便,需要先通過 LocalBroadcastManager.getInstance() 方法獲取其單例,剩下的用法與其他廣播類似,其主要方法有以下幾個:

  • registerReceiver():註冊廣播接收器。
  • unregisterReceiver():解除廣播接收器。
  • sendBroadcast():發送異步廣播。
  • sendBroadcastSync():發送同步廣播。

使用本地廣播時,無需在AndroidMainfest.xml中註冊,必須使用 LocalBroadcastManager.getInstance(...).registerReceiver(..)來註冊接收器。

我們來寫個本地廣播的小栗子,首先註冊兩個本地廣播:

LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcast2Receiver(), new IntentFilter(MyBroadcastReceiver.ACTION));

然後發送本地廣播:

intent.putExtra(INTENT_INFO, "我是一個本地廣播");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

log如下:

12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到廣播消息:我是一個本地廣播
12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到廣播消息:我是一個本地廣播

四、sticky廣播(不建議使用)

sticky廣播會一直處於滯留狀態,sticky廣播被發出後,只要有能夠匹配其的新接收器被註冊了就可以收到廣播,sticky廣播通過Context.sendStickyBroadcast()發送。


最後想說的是,本系列文章為博主對Android知識進行再次梳理,查缺補漏的學習過程,一方面是對自己遺忘的東西加以復習重新掌握,另一方面相信在重新學習的過程中定會有巨大的新收獲,如果你也有跟我同樣的想法,不妨關註我一起學習,互相探討,共同進步!

參考文獻:

  • 《Android開發藝術探索》
  • 《Android開發進階從小工到專家》

Android查缺補漏--BroadcastReceiver的類型與使用