Android中BroadCastReceiver廣播接收者
BroadCastReceiver 源碼位于: framework/base/core/java/android.content.BroadcastReceiver.java
廣 播接收者( BroadcastReceiver )用于接收廣播 Intent ,廣播 Intent 的發(fā)送是通過調用 Context.sendBroadcast() 、 Context.sendOrderedBroadcast() 來實現的。通常一個廣播 Intent 可以被訂閱了此 Intent 的多個廣播接收者所接收。
廣播是一種廣泛運用的在應用程序之間傳輸信息的機制 。而 BroadcastReceiver 是對發(fā)送出來的廣播進行過濾接收并響應的一類組件;
來自普通應用程序,如一個應用程序通知其他應用程序某些數據已經下載完畢。
BroadcastReceiver 自身并不實現圖形用戶界面,但是當它收到某個通知后, BroadcastReceiver 可以啟動 Activity 作為響應,或者通過 NotificationMananger 提醒用戶,或者啟動 Service 等等。
在 Android 里面有各種各樣的廣播,比如電池的使用狀態(tài),電話的接收和短信的接收都會產生一個廣播,應用程序開發(fā)者也可以監(jiān)聽這些廣播并做出程序邏輯的處理。如圖:
用接收短信舉例:
第一種方式 :
實現
public class MyBroadcastReceiver extends BroadcastReceiver {
// action 名稱
String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED" ;
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals( SMS_RECEIVED )) {
// 相關處理 : 地域變換、電量不足、來電來信;
}
}
}
系統注冊:在 AndroidManifest.xml 中注冊
< receiver android:name = ".MyBroadcastReceiver" >
< intent-filter android:priority = "1000" >
< action android:name = " android.provider.Telephony.SMS_RECEIVED" />
</ intent-filter >
</ receiver > 當然了需要權限 :
< uses-permission android:name = "android.permission.RECEIVE_SMS" />
< uses-permission android:name = "android.permission.SEND_SMS" />
第二種方式:
// 廣播接收者 - 廣播的接收
private BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 相關處理,如收短信,監(jiān)聽電量變化信息
}
};
代碼中注冊:
IntentFilter intentFilter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED " );
registerReceiver( mBatteryInfoReceiver , intentFilter);
描述了 Android 中廣播的生命周期,其次它并不像 Activity 一樣復雜,運行原理很簡單如下圖:
生命周期只有十秒左右,如果在 onReceive() 內做超過十秒內的事情,就會報錯 。
每 次廣播到來時 , 會重新創(chuàng)建 BroadcastReceiver 對象 , 并且調用 onReceive() 方法 , 執(zhí)行完以后 , 該對象即被銷毀 . 當 onReceive() 方法在 10 秒內沒有執(zhí)行完畢, Android 會認為該程序無響應 . 所以在
BroadcastReceiver 里不能做一些比較耗時的操作 , 否側會彈出 ANR(Application No
Response) 的對話框 . 。(如圖):
怎么用好 BroadcastReceiver ?
如果需要完成一項比較耗時的工作 , 應該通過發(fā)送 Intent 給 Service, 由 Service 來完成 . 這里不能使用子線程來解決 , 因為 BroadcastReceiver 的生命周期很短 , 子線程可能還沒有結束
BroadcastReceiver 就先結束了 .BroadcastReceiver 一旦結束 , 此時 BroadcastReceiver 的
所在進程很容易在系統需要內存時被優(yōu)先殺死 , 因為它屬于空進程 ( 沒有任何活動組件的進程 ). 如果它的宿主進程被殺死 , 那么正在工作的子線程也會被殺死 . 所以采用子線程來解決是不可靠的 .
普通廣播 (Normal broadcasts)
發(fā)送一個廣播,所以監(jiān)聽該廣播的廣播接收者都可以監(jiān)聽到改廣播。
異步廣播 , 當處理完之后的Intent ,依然存在,這時候registerReceiver(BroadcastReceiver, IntentFilter) 還能收到他的值,直到你把它去掉 , 不能將處理結果傳給下一個接收者 , 無法終止廣播 .
有序廣播 (Ordered broadcasts)
按照接收者的優(yōu)先級順序接收廣播 , 優(yōu)先級別在 intent-filter 中的 priority 中聲明 ,-1000 到
1000 之間 , 值越大 , 優(yōu)先級越高 . 可以終止廣播意圖的繼續(xù)傳播 . 接收者可以篡改內容 .
該組件接收被廣播的 intent,Context 可以通過 sendBroadcast() 和 sendOrderedBroadcast()
方法實現廣播的發(fā)送 .
首先在需要發(fā)送信息的地方 ,把要發(fā)送的信息和用于過濾的信息 ( 如 Action 、 Category) 裝入一個 Intent 對象 ,然后通過調用 Context.sendBroadcast() 、 sendOrderBroadcast() 或 sendStickyBroadcast() 方法,把 Intent 對象以廣播方式發(fā)送出去。
使用 sendBroadcast() 或 sendStickyBroadcast() 方法發(fā)出去的 Intent ,所有滿足條件的 BroadcastReceiver 都會隨機地執(zhí)行其 onReceive() 方法
sendBroadcast(intent);
Intent intent = new Intent( "cn.lenovo.yangguangf " );
sendBroadcast(intent);
priority :這個是 AndroidManifest.xml 中 intent-filter 的參數。
< receiver android:name = ".MyBroadcastReceiver" >
< intent-filter android:priority = "1000" >
< action android:name = "cn.lenovo.yangguangfu" />
</ intent-filter >
</ receiver >
sendOrderedBroadcast(intent, receiverPermission);
1 ,他決定該廣播的級別,級別數值是在 -1000 到 1000 之間 , 值越大 , 優(yōu)先級越高;
2 ,同級別接收是先后是隨機的;級別低的收到廣播;
3 ,在 android 系統中只要監(jiān)聽該廣播的接收者,都能夠收到 sendBroadcast(intent) 發(fā)出的廣播 ;
3 ,不能截斷廣播的繼續(xù)傳播,
4 ,實驗現象,在這個方法發(fā)來的廣播中,代碼注冊方式中,收到的廣播的先后和注明優(yōu)先級最高的他們的先后是隨機。如果都沒有優(yōu)先級,代碼注冊收到為最先。
sendOrderedBroadcast(intent, receiverPermission);
sendOrderedBroadcast(intent, receiverPermission, resultReceiver,
scheduler, initialCode, initialData, initialExtras)
意圖,廣播,所有匹配的這一意圖將接收機接收廣播。
receiverPermission 這是權限,一個接收器必須持以接收您的廣播。如果為 null ,不經許可的要求。
resultReceiver 您自己 BroadcastReceiver 來當作最后的廣播接收器。
調度自定義處理程序,用以安排 resultReceiver 回調 ; 如果為 null 將語境中的主線程舉行。
initialCode 一種結果代碼的初始值。通常為 Activity.RESULT_OK 。這個值是 -1 ;為其他 int 型 也可以,如 0,1,2 ;
initialData 一種結果數據的初始值。通常情況下為空 , 是 String 類型 ;
initialExtras 一種結果額外的初始值。通常情況下為空 , 是 Bundle;
intent The Intent to broadcast; all receivers matching this Intent will receive the broadcast.
receiverPermission String naming a permissions that a receiver must hold in order to receive your broadcast. If null, no permission is required.
resultReceiver Your own BroadcastReceiver to treat as the final receiver of the broadcast.
scheduler A custom Handler with which to schedule the resultReceiver callback; if null it will be scheduled in the Context's main thread.
initialCode An initial value for the result code. Often Activity.RESULT_OK.
initialData An initial value for the result data. Often null.
initialExtras An initial value for the result extras. Often null.
1, 該廣播的級別有級別之分,級別數值是在 -1000 到 1000 之間 , 值越大 , 優(yōu)先級越高;
2, 同級別接收是先后是隨機的,再到級別低的收到廣播;
3, 同級別接收是先后是隨機的,如果先接收到的把廣播截斷了,同級別的例外的接收者是無法收到該廣播的。( abortBroadcast() )
4 ,能截斷廣播的繼續(xù)傳播,高級別的廣播收到該廣播后,可以決定把該鐘廣播是否截斷掉。
5 ,實驗現象,在這個方法發(fā)來的廣播中,代碼注冊方式中,收到廣播先后次序為:注明優(yōu)先級的、代碼注冊的、沒有優(yōu)先級的;如果都沒有優(yōu)先級,代碼注冊收到為最先。
sendStickyBroadcast(intent);
當處理完之后的Intent ,依然存在,直到你把它去掉。
發(fā)這個廣播需要權限<uses-permission android:name="android.permission.BROADCAST_STICKY" />
去掉是用這個方法removeStickyBroadcast(intent); 但別忘了在執(zhí)行這個方法的應用里面 AndroidManifest.xml 同樣要加上面的權限;
sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,
initialCode, initialData, initialExtras)
這個方法具有有序廣播的特性也有異步廣播的特性;
發(fā)送這個廣播要: <uses-permission android:name="android.permission.BROADCAST_STICKY" /> 這個權限。才能使用這個方法。如果您并不擁有該權限,將拋出 SecurityException 的。
實驗現象( sendStickyOrderedBroadcast ()中),在這個方法發(fā)來的廣播中,代碼注冊方式中,收到廣播先后次序為:注明優(yōu)先級的、代碼注冊的、沒有優(yōu)先級的;如果都沒有優(yōu)先級,代碼注冊收到為最先。
注 冊廣播方法一: registerReceiver(BroadcastReceiver receiver, IntentFilter filter) ,第一個參數是我們要處理廣播的 BroadcastReceiver (廣播接收者,可以是系統的,也可以是自定義的);第二個參數是意圖過濾器。
注冊廣播方法二: registerReceiver(receiver, filter, broadcastPermission, scheduler) ,第一個參數是 BroadcastReceiver (廣播接收者,可以是系統的,也可以是自定義的);第二個參數是意圖過濾器;第三個參數是廣播權限;第四個參數是 Hander ;
注意:權限重復現象,如果功能清單文件里注冊了權限,在該方法再注冊,則 receiver 無法收到廣播,如果 功能清單文件里沒有注冊了權限,該方法注冊也無法收到。當該方法沒有注冊權限,功能清單里注冊的時候, receiver 能收到廣播。
總結:在 Activity 中代碼注冊廣播建議在: onResume() 中注冊;
思 維拓展: 1 ,如果在代碼調用 registerReceiver(BroadcastReceiver receiver, IntentFilter filter) 十次( receiver , filter 的參數是同一參數),那么是否當該廣播發(fā)送來的時候會收到十次呢?
2 ,注銷是否也要注銷十次才能把廣播全部注銷呢?
< receiver android:name = ".MyBroadcastReceiver" >
< intent-filter android:priority = "900" >
< action android:name = "cn.lenovo.yangguangfu" />
</ intent-filter >
</ receiver >
有時候還要根據發(fā)送廣播是否指定權限,來決定是否要權限;
// 代碼中注銷廣播
/unregisterReceiver(mBatteryInfoReceiver);
?
在 Activity 中代碼注銷廣播建議在: onPuase() 中注銷;
不要這這里面注銷 Activity.onSaveInstanceState(), 因為這個方法是保存 Intent 狀態(tài)的。
這個方法可以截獲由 sendOrderedBroadcast () 發(fā)送來的 廣播,讓其它廣播接收者無法收到這個廣播。
這個方法是針對上面的 abortBroadcast() 方法的,用于取消截獲廣播。這樣它的下一級廣播接收者就能夠收到該廣播了。
這 個方法作用是:判斷是否調用了 abortBroadcast (),如果先調用 abortBroadcast (),接著再調用 getAbortBroadcast (),將返回 true; 如果在調用 abortBroadcast() 、 clearAbortBroadcast ()
getAbortBroadcast (),將返回 false;
Since: API Level 1
Return the last value given to setDebugUnregister(boolean)
.
如果用下面四個方法發(fā)送得廣播,返回碼為: -1 ;
// sendBroadcast(intent);
// sendBroadcast(intent, receiverPermission);
// sendOrderedBroadcast(intent, receiverPermission);
// sendStickyBroadcast(intent);
如果用下面兩個方法發(fā)送得廣播,返回碼為:根據你設置 initialCode 的數字是多少就是多少;
// sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,
// initialCode, initialData, initialExtras)
// sendOrderedBroadcast(intent, receiverPermission, resultReceiver,
// scheduler, initialCode, initialData, initialExtras)
得到發(fā)送廣播時設置的 initialData 的數據;
If true then a new empty Map will be made for you if the current Map is null; if false you should be prepared to receive a null Map.
得到由
sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,
// initialCode, initialData, initialExtras) ;
// sendOrderedBroadcast(intent, receiverPermission, resultReceiver,
// scheduler, initialCode, initialData, initialExtras)
中 initialExtras 傳入的參數。
實驗:我用上面兩個方法發(fā)了 initialExtras (這個一個 Bundle )傳入的參數時,只要不為空,那么 makeMap 是否為 true 和 false 都能夠得到數據。
Returns true if the receiver is currently processing the initial value of a sticky broadcast -- that is, the value that was last broadcast and is currently held in the sticky cache, so this is not directly the result of a broadcast right now.
如果廣播接收者是目前處理的一個宿主的廣播的初始值,將返回 true , - 也就是說,這個值是最后的廣播出的值,目前正在舉行的宿主緩存,所以這并不是直接導致了現在的廣播。
實驗:在第三個應用中調用這個方法,無論你用哪種方式發(fā)送廣播,這個方法得到的總是 false ;在發(fā)送廣播 的 resultReceiver 廣播接收者里面調用,得到的也是 false ;
sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,
initialCode, initialData, initialExtras)
上面這個方法發(fā)送時,得到的是 true;
判斷是否是有序廣播;
Provide a binder to an already-running service. This method is synchronous and will not start the target service if it is not present, so it is safe to call from onReceive.
Parameters:
myContext The Context that had been passed to onReceive(Context, Intent)
service The Intent indicating the service you wish to use. See Context.startService(Intent) for more information.
Control inclusion of debugging help for mismatched calls to {@ Context#registerReceiver(BroadcastReceiver, IntentFilter) Context.registerReceiver()}. If called with true, before given to registerReceiver(), then the callstack of the following Context.unregisterReceiver()
call is retained, to be printed if a later incorrect unregister call is made. Note that doing this requires retaining information about the BroadcastReceiver for
推薦文章
2025-01-18
2024-11-28
2024-11-09
2024-10-25
2024-06-25
2024-01-04
2023-11-06
2023-10-30
2023-10-13
2023-10-10
穩(wěn)定
產品高可用性高并發(fā)貼心
項目群及時溝通專業(yè)
產品經理1v1支持快速
MVP模式小步快跑承諾
我們選擇聲譽堅持
10年專注高端品質開發(fā)