廣播接收器:Broadcast Receiver
今天帶來 Android 第三大組件——Broadcast Receiver,可以用于和自己或者其他 App 發(fā)送消息,和 Service 一樣,它也沒有自己的 UI 界面。Broadcast Receiver 的設(shè)計模式非常類似發(fā)布/訂閱模式,可用于做進程間通信(IPC)。通過本節(jié)的學習你可以詳細的了解到 Android 中廣播的作用和使用方法,并且能夠?qū)⑵潇`活的運用到實際開發(fā)中。
1. 什么是廣播接收器
首先看看官方文檔的部分解釋:
Base class for code that receives and handles broadcast intents sent by Context.sendBroadcast(Intent).
You can either dynamically register an instance of this class with Context.registerReceiver() or statically declare an implementation with the tag in your AndroidManifest.xml.
簡單翻譯如下:
Broadcast Receiver 是一個基類,繼承自它的類可以用來處理通過
Context.sendBroadcast(Intent)
發(fā)送過來的 intent 信息。與其他組件不同的是,Broadcast Receiver 支持動態(tài)注冊,即你可以在代碼里調(diào)用Context.registerReceiver()
來注冊廣播接收器,也可以和 Activity、Service 一樣使用靜態(tài)注冊的方式,即在 AndroidManifest.xml 文件中進行注冊。
這是從“Broadcast Receiver”文檔里面截取的一部分,解釋的不是很全面。簡而言之就是 Android 系統(tǒng)為我們提供了各式各樣系統(tǒng)廣播,用來給所有 App 推送一些全局消息,如:網(wǎng)絡(luò)切換、電量變化、耳機插拔、藍牙斷開等等。如果 App 希望獲得這些事件,那么可以提前注冊一個廣播接收器,然后就能收到相應(yīng)類型的廣播了。同時我們還可以自定義一些類型,比如上一節(jié)中的音樂播放器,我們可以定義“切歌”為一個廣播事件,然后可供其他 App,或者 App 內(nèi)其他頁面去接收。
2. 系統(tǒng)類型廣播
在學習自定義廣播之前,我們先來看看一些常用的系統(tǒng)廣播,通常都是發(fā)送一些系統(tǒng)相關(guān)的事件:
- android.intent.action.BATTERY_CHANGED:
通知電量變化,可以獲取電量百分比等相關(guān)數(shù)據(jù) - android.intent.action.BATTERY_LOW:
低電通知 - android.intent.action.POWER_CONNECTED:
充電器連接 - android.intent.action.POWER_DISCONNECTED:
充電器斷開 - android.intent.action.BOOT_COMPLETED:
設(shè)備啟動 - android.intent.action.DATE_CHANGED:
設(shè)備時間修改 - android.intent.action.REBOOT:
設(shè)備重啟 - android.intent.action.CONNECTIVITY_CHANGE:
網(wǎng)絡(luò)環(huán)境變化,可以從“intent”中解析出具體的網(wǎng)絡(luò)類型 - android.intent.action.BUG_REPORT:
bug 上報事件 - android.intent.action.CALL_BUTTON:
用戶點擊的撥打電話按鍵
3. Broadcast 的類型
在 Android 中有兩種類型的廣播:
- 有序廣播
- 無序廣播
下面分別來介紹這兩類廣播。
3.1 有序廣播
顧名思義,有序廣播是按照一定的順序同步進行發(fā)送的,也就是每一個 Broadcast Receiver 是按照順序一個一個的收到消息。而這個順序優(yōu)先級依賴于android:priority
屬性,我們可以在 AndroidManifest.xml 中注冊的時候配置優(yōu)先級,當然優(yōu)先級越高的 Receiver 會更早的接收到廣播,同優(yōu)先級的 Receiver 順序隨機。
在這種情況下,一個廣播在一個時間點只會被發(fā)送給一個 Receiver。當一個 Receiver 收到廣播只會,它可以決定讓這條廣播繼續(xù)向更低優(yōu)先級的 Receiver 發(fā)送,或者可以攔截掉這條 Receiver,換言之,高優(yōu)先級的 Receiver 可以決定低優(yōu)先級的 Receiver 是否還能收到廣播。
3.2 無序廣播
理解了有序廣播之后,無序廣播就很容易理解了。無需廣播就是沒有任何優(yōu)先級之分,所有廣播都是異步同時發(fā)送,此時 Receiver 的接收時序也是完全隨機的。正因為異步且無需保證時序,所以無需廣播更高效,但是不能在各個 Receiver 之間傳遞數(shù)據(jù)。
4 Broadcast Receiver 的使用示例
為了打造一個更好的 App,我們需要充分的發(fā)揮廣播的優(yōu)勢,因為它足夠靈活,足夠強大。
下面我們一起寫一個通過 Broadcast Receiver 發(fā)送消息的例子,用戶在輸入框輸入的消息,我們通過廣播發(fā)送出去,最后在廣播接收器中進行解析并打印輸入的內(nèi)容。
4.1 注冊
Broadcast Receiver 是四大組件中唯一一個支持動態(tài)注冊的組件,我們可以在代碼中通過Context.registerReceiver()
方法進行注冊:
IntentFilter filter = new IntentFilter();
intentFilter.addAction(getPackageName()+"com.emercy.CUSTOM_RECEIVER");
MyReceiver myReceiver = new MyReceiver();
registerReceiver(myReceiver, filter);
同時,也支持類似 Activity、Service 的靜態(tài)注冊方式,在 AndroidManifest.xml 中添加以下注冊代碼:
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="com.emercy.CUSTOM_RECEIVER" />
</intent-filter>
</receiver>
4.2 廣播接收器
注冊之后我們就可以放心的編寫我們的廣播接收器了,方法很簡單:首先創(chuàng)建一個類繼承自BroadcastReceiver
,然后覆寫onReceive(Context context, Intent intent)
方法,其中廣播傳遞的參數(shù)就在 intent 當中,我們可以在 onReceive() 方法中取出,代碼如下:
package com.emercy.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class MyBroadcastReceiver extends BroadcastReceiver {
static final String BROADCAST_INTENT = "com.emercy.CUSTOM_RECEIVER";
@Override
public void onReceive(Context context, Intent intent) {
CharSequence data = intent.getCharSequenceExtra("msg");
Toast.makeText(context, "接收到的消息: " + data, Toast.LENGTH_LONG).show();
}
}
通過intent.getCharSequenceExtra()
方法獲取廣播中的參數(shù),然后通過 Toast 進行打印即可。
4.3 布局文件編寫
布局文件主要有兩個關(guān)鍵點:
- 添加一個輸入框 EditText,用于接收用戶的輸入;
- 添加一個 Button,用于觸發(fā)廣播的發(fā)送,同時獲取 EditText 中輸入的內(nèi)容放入 intent 中。如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginStart="100dp"
android:layout_marginTop="150dp"
android:text="廣播接收器"
android:textColor="#a4c639"
android:textSize="50sp" />
<EditText
android:id="@+id/textMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="270dp"
android:ems="10" />
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="130dp"
android:layout_marginTop="310dp"
android:text="發(fā)送廣播" />
</RelativeLayout>
4.4 發(fā)送廣播
MainActivity 主邏輯的任務(wù)就很明顯了,接收用戶的輸入,塞入 intent 并通過 Broadcast 發(fā)送出去:
package com.emercy.myapplication;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import static com.emercy.myapplication.MyBroadcastReceiver.BROADCAST_INTENT;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText st = findViewById(R.id.textMsg);
// 將EditText的內(nèi)容塞到Intent里,通過廣播發(fā)出去
Intent intent = new Intent();
intent.putExtra("msg", (CharSequence) st.getText().toString());
intent.setAction(BROADCAST_INTENT);
sendBroadcast(intent);
}
});
}
}
編譯運行,在 EditText 中輸入任意字符,然后點擊“發(fā)送廣播”,此時 MyBroadcastReceiver 中的 onReceive()
方法被觸發(fā),從而將我們輸入的內(nèi)容 Toast 出來,如圖:
5 小結(jié)
本節(jié)學習的是 Android 第三個組件,Android 預(yù)置了很多個系統(tǒng)廣播,主要用于讓 App 很方便的接收一些系統(tǒng)事件。廣播分為有序廣播和無序廣播,有序廣播會按照優(yōu)先級順序依次發(fā)送給 Receiver,而無序廣播則是同時發(fā)送,相比之下無序廣播的效率更高,但是不可控。如果希望自定義廣播,可以直接創(chuàng)建一個 BroadcastReceiver 的子類,覆寫onReceive()
,這樣就可以從 intent 中取到數(shù)據(jù)了。使用廣播,可以很方便的在應(yīng)用內(nèi)、應(yīng)用間傳遞消息,對功能解耦、事件傳遞等場景非常適用,你學會了嗎?