Android入门(11)| 全局广播与本地广播
文章目錄
- 廣播概念
- 接收廣播
- 動(dòng)態(tài)注冊(cè)
- 實(shí)例
- 靜態(tài)注冊(cè)
- 實(shí)例
- 發(fā)送廣播
- 發(fā)送標(biāo)準(zhǔn)廣播
- 廣播的跨進(jìn)程特性
- 發(fā)送有序廣播
- 本地廣播
廣播概念
Android 中的每個(gè)應(yīng)用程序都可以對(duì)自己感興趣的廣播進(jìn)行注冊(cè),這樣該程序就只會(huì)接收到自己所關(guān)心的廣播內(nèi)容,這些廣播可能是來自系統(tǒng)的,也可能是來自于其他應(yīng)用程序的。
廣播有兩種類型——有序廣播和標(biāo)準(zhǔn)廣播:
- 標(biāo)準(zhǔn)廣播: 一種完全異步執(zhí)行的廣播,在廣播發(fā)出去之后,所有的廣播接收器幾乎都會(huì)同一時(shí)刻接收到這條廣播消息,沒有任何的先后順序可言,這種廣播的效率比較高,但是無法被截?cái)?/strong>。
- 有序廣播: 是一種同步執(zhí)行的廣播,在廣播發(fā)出去之后,同一時(shí)刻只會(huì)有一個(gè)廣播接收器能夠收到這條消息,當(dāng)這個(gè)廣播接收器中的邏輯執(zhí)行完畢之后,廣播才會(huì)繼續(xù)傳遞,所以這時(shí)候的廣播接收器是有優(yōu)先級(jí)順序的,并且前面的廣播接收器還可以截?cái)?/strong>正在傳遞的廣播,這樣后面的廣播就無法收到廣播消息。
接收廣播
動(dòng)態(tài)注冊(cè)
Android內(nèi)置了很多系統(tǒng)級(jí)別的廣播,我們可以在應(yīng)用程序中通過監(jiān)聽這些廣播來得到各種系統(tǒng)的狀態(tài)信息。比如手機(jī)開機(jī)、電池電量發(fā)生變化、時(shí)間或者時(shí)區(qū)發(fā)生改變等等。如果想要接收到這些廣播就需要使用廣播接收器。
注冊(cè)廣播的方式一般也有兩種,在 代碼中注冊(cè)(動(dòng)態(tài)注冊(cè)) 或者 在 AndroidManifest.xml 中注冊(cè)(靜態(tài)注冊(cè))。
實(shí)例
我們實(shí)現(xiàn)一個(gè)能準(zhǔn)確地告訴用戶當(dāng)前有沒有網(wǎng)絡(luò)的功能,在實(shí)現(xiàn)代碼前,由于 Android 為了保護(hù)用戶設(shè)備的隱私和安全,規(guī)定了程序需要進(jìn)行一些對(duì)用戶來說比較敏感的操作,必須在配置文件中聲明權(quán)限才可以,該功能監(jiān)聽了網(wǎng)絡(luò)的變化,所以必須在 AndroidManifest.xml 配置權(quán)限才能訪問系統(tǒng)網(wǎng)絡(luò)狀態(tài):
靜態(tài)注冊(cè)
動(dòng)態(tài)注冊(cè)的廣播可以自由控制注冊(cè)、注銷,很靈活,缺點(diǎn)是必須在程序啟動(dòng)之后才能接受到廣播,因?yàn)樽?cè)的邏輯是寫在 onCreate() 里面的,使用靜態(tài)注冊(cè)可以讓程序在未啟動(dòng)的情況下接受到廣播。
實(shí)例
靜態(tài)注冊(cè)需要在 AndroidManifest.xml 進(jìn)行注冊(cè),使用 receiver 標(biāo)簽,并告訴這個(gè) receiver 注冊(cè)哪一個(gè) action,下面是一個(gè)開機(jī)啟動(dòng)接受廣播的案例:
public class BootCompleteReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO: This method is called when the BroadcastReceiver is receiving// an Intent broadcast.Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show();} }PS:不要在 onReceive() 方法中添加過多邏輯或耗時(shí)操作,因?yàn)閺V播接收器中不允許開啟線程,因此當(dāng) onReceive() 運(yùn)行較長(zhǎng)時(shí)間卻未結(jié)束時(shí),程序就會(huì)報(bào)錯(cuò)。
發(fā)送廣播
發(fā)送標(biāo)準(zhǔn)廣播
發(fā)送廣播使用 Intent 進(jìn)行發(fā)送,首先需要準(zhǔn)備一個(gè)接收器用于接受發(fā)送的廣播:
public class MyBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 收到自定義廣播時(shí)會(huì)彈出提示Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_LONG).show();} }在 AndroidManifest.xml 中注冊(cè)廣播的值:
實(shí)現(xiàn)點(diǎn)擊 BroadcastActivity 活動(dòng)中的 send broadcast 按鈕來發(fā)送廣播:
布局文件 broad_layout.xml:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button_broadcast1"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="send broadcast"/> </LinearLayout>活動(dòng)代碼 BroadcastActivity.java:
public class BroadcastActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.broad_layout);Button button = findViewById(R.id.button_broadcast1);button.setOnClickListener((View v)->{// 將要發(fā)送的廣播植入IntentIntent intent = new Intent("com.example.activitytest.Activity.MY_BROADCAST");// 參數(shù)1:包名;參數(shù)2:接收器的路徑ComponentName componentName = new ComponentName("com.example.activitytest","com.example.activitytest.Activity.MyBroadcastReceiver");// 通過調(diào)用Intent中的setComponent方法,我們可以打開另外一個(gè)應(yīng)用中的Activity或者服務(wù)。intent.setComponent(componentName);// 調(diào)用Context的sendBroadcast方法發(fā)送廣播sendBroadcast(intent);});} }PS: ComponentName 構(gòu)造函數(shù)的第一個(gè)參數(shù)指的包名是 AndroidManifest.xml 文件下 package 屬性對(duì)應(yīng)的包名:
而非 BroadcastActivity.java 文件所在的包名:
詳見該博客
運(yùn)行結(jié)果:
廣播的跨進(jìn)程特性
新建一個(gè)項(xiàng)目,創(chuàng)建廣播接收器 MyReceiver.java :
public class MyReceiver extends BroadcastReceiver {private static final String TAG = "MyReceiver";@Overridepublic void onReceive(Context context, Intent intent) {Log.e(TAG, "onReceive: gone");Toast.makeText(context, "received gone", Toast.LENGTH_LONG).show();} }AndroidManifest.xml :
在原來項(xiàng)目的 BroadcastActivity.java 文件中發(fā)送第二條廣播:
運(yùn)行結(jié)果:
更多關(guān)于廣播的問題詳見本文——解決 Android 8.0 以上靜態(tài)廣播無法注冊(cè)
發(fā)送有序廣播
很多人對(duì)之前的代碼可能會(huì)有疑問,我指定廣播發(fā)送給哪個(gè)包的哪個(gè)接收器,這還算“廣播”嗎?因此,對(duì)于安卓高版本而言,還有另一種發(fā)送廣播的方法:
修改 BroadcastActivity.java 中的代碼:
即可實(shí)現(xiàn)真正意義上的廣播。在此基礎(chǔ)上,我們發(fā)送有序廣播,定義接收器的優(yōu)先級(jí):
并在接收器 MyBroadcastReceiver.java 中截?cái)鄰V播,不允許廣播繼續(xù)傳遞:
不必對(duì)另一個(gè)接收器 MyReceiver 進(jìn)行更改,此時(shí)就已達(dá)到了只有 MyBroadcastReceiver 能收到廣播,而 MyReceiver 不能收到廣播的目的。
本地廣播
前面我們發(fā)送和接受的廣播都是系統(tǒng)的全局廣播,發(fā)出的廣播可以被其他任何應(yīng)用程序接收到。這樣容易引起安全問題,為了解決安全性問題,Android 支持發(fā)送本地廣播,其有以下特點(diǎn):
- 廣播不會(huì)離開我們的程序,無需擔(dān)心機(jī)密數(shù)據(jù)泄露;
- 其他程序的廣播無法發(fā)送到我們程序內(nèi)部,無需擔(dān)心有安全漏洞的隱患;
- 比發(fā)送全局廣播更高效。
- 本地廣播的接收只能使用動(dòng)態(tài)注冊(cè),因?yàn)?strong>靜態(tài)注冊(cè)就是為了讓程序在未啟動(dòng)的時(shí)候也能接收到廣播,而發(fā)送本地廣播的時(shí)候應(yīng)用程序肯定啟動(dòng)了。
本地廣播并不復(fù)雜,主要就是使用了一個(gè) LocalBroadcastManager 來對(duì)廣播進(jìn)行管理,并且提供了發(fā)送廣播和注冊(cè)廣播接收器的方法:
public class BroadcastActivity extends AppCompatActivity {private static final String TAG = "BroadcastActivity";private IntentFilter intentFilter; // 意圖過濾器private LocalReceiver localReceiver; // 自定義接收器類private LocalBroadcastManager localBroadcastManager; // support包提供的本地廣播工具@SuppressLint("WrongConstant")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.broad_layout);localBroadcastManager = LocalBroadcastManager.getInstance(this); // 獲取實(shí)例Button button = findViewById(R.id.button_broadcast1);button.setOnClickListener((View v)->{Log.e(TAG, "onCreate: start");// 將要發(fā)送的廣播植入IntentIntent intent = new Intent("com.example.activitytest.Activity.LOCAL_BROADCAST");if(Build.VERSION.SDK_INT >= 28){// 突破隱式廣播限制intent.addFlags(0x01000000);}localBroadcastManager.sendBroadcast(intent); // 發(fā)送本地廣播});// 動(dòng)態(tài)注冊(cè)的步驟intentFilter = new IntentFilter();// 添加自定義廣播intentFilter.addAction("com.example.activitytest.Activity.LOCAL_BROADCAST");// 實(shí)例化接收器localReceiver = new LocalReceiver();// 注冊(cè)接收器localBroadcastManager.registerReceiver(localReceiver, intentFilter);}// 動(dòng)態(tài)注冊(cè)一定要在結(jié)束時(shí)取消注冊(cè)@Overrideprotected void onDestroy() {super.onDestroy();localBroadcastManager.unregisterReceiver(localReceiver);}class LocalReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "本地廣播", Toast.LENGTH_LONG).show();}} }總結(jié)
以上是生活随笔為你收集整理的Android入门(11)| 全局广播与本地广播的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广发银行ONE卡麦兜联名信用卡年费多少?
- 下一篇: 广发I购花怎么申请?三种方法都可办理