Android 中的BroadCastReceiver

BroadCastReceiver 簡介 (末尾有源碼)

BroadCastReceiver 源碼位於:  framework/base/core/java/android.content.BroadcastReceiver.java  java

 

廣播接收者( BroadcastReceiver  )用於接收廣播 Intent ,廣播 Intent  的發送是經過調用 Context.sendBroadcast() 、  Context.sendOrderedBroadcast() 來實現的。一般一個廣播  Intent 能夠被訂閱了此 Intent  的多個廣播接收者所接收。android

 

廣播是一種普遍運用的在應用程序之間傳輸信息的機制 。而  BroadcastReceiver 是對發送出來的廣播進行過濾接收並響應的一類組件;緩存

 

來自普通應用程序,如一個應用程序通知其餘應用程序某些數據已經下載完畢。異步

 BroadcastReceiver  自身並不實現圖形用戶界面,可是當它收到某個通知後, BroadcastReceiver  能夠啓動 Activity 做爲響應,或者經過  NotificationMananger 提醒用戶,或者啓動 Service  等等。ide

BroadCastReceiver 的機制

1. 機制

在 Android  裏面有各類各樣的廣播,好比電池的使用狀態,電話的接收和短信的接收都會產生一個廣播,應用程序開發者也能夠監聽這些廣播並作出程序邏輯的處理。如圖:  ui


 

2. 實現

用接收短信舉例:this

 

第一種方式 spa

實現 線程

public class MyBroadcastReceiver extends BroadcastReceiver { debug

 

    //  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)  {

           // 相關處理,如收短信,監聽電量變化信息

       }

 

    };

 

代碼中註冊:

IntentFilter intentFilter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED " );

registerReceiver( mBatteryInfoReceiver , intentFilter);

 

3. 生命週期

 

描述了 Android  中廣播的生命週期,其次它並不像 Activity  同樣複雜,運行原理很簡單以下圖:


 

 

生命週期只有十秒左右,若是在  onReceive()  內作超過十秒內的事情,就會報錯

 

每次廣播到來時 , 會從新建立  BroadcastReceiver 對象 , 而且調用  onReceive() 方法 , 執行完之後  , 該對象即被銷燬 . 當  onReceive() 方法在 10 秒內沒有執行完畢,  Android 會認爲該程序無響應 . 因此在

BroadcastReceiver 裏不能作一些比較耗時的操做  , 否側會彈出 ANR(Application No

Response) 的對話框 .  。(如圖):

 

怎麼用好  BroadcastReceiver ?  

若是須要完成一項比較耗時的工做 ,  應該經過發送 Intent 給 Service,  由 Service 來完成 .  這裏不能使用子線程來解決 , 由於  BroadcastReceiver 的生命週期很短 ,  子線程可能尚未結束

BroadcastReceiver 就先結束了  .BroadcastReceiver 一旦結束 , 此時  BroadcastReceiver 的

所在進程很容易在系統須要內存時被優先殺死 ,  由於它屬於空進程 ( 沒有任何活動組件的進程 ).  若是它的宿主進程被殺死 , 那麼正在工做的子線程也會被殺死  . 因此採用子線程來解決是不可靠的 .

 

廣播類型及廣播的收發

廣播類型

普通廣播 (Normal  broadcasts)

   發送一個廣播,因此監聽該廣播的廣播接收者均可以監聽到改廣播。

異步廣播  , 當處理完以後的Intent  ,依然存在,這時候registerReceiver(BroadcastReceiver, IntentFilter)  還能收到他的值,直到你把它去掉 , 不能將處理結果傳給下一個接收者  , 沒法終止廣播 .

 

有序廣播 (Ordered  broadcasts)

按照接收者的優先級順序接收廣播 ,  優先級別在 intent-filter 中的  priority 中聲明 ,-1000 到

1000 之間 ,  值越大 , 優先級越高 .  能夠終止廣播意圖的繼續傳播 . 接收者能夠篡改內容 .  

 

 

 

廣播的收發

該組件接收被廣播的 intent,Context  能夠經過 sendBroadcast() 和  sendOrderedBroadcast()

方法實現廣播的發送 .

首先在須要發送信息的地方  ,把要發送的信息和用於過濾的信息 ( 如  Action 、 Category)  裝入一個 Intent 對象  ,而後經過調用 Context.sendBroadcast()  、 sendOrderBroadcast() 或  sendStickyBroadcast() 方法,把 Intent  對象以廣播方式發送出去。

 

使用 sendBroadcast() 或  sendStickyBroadcast() 方法發出去的 Intent  ,全部知足條件的 BroadcastReceiver 都會隨機地執行其  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 之間 , 值越大 , 優先級越高;

 

2  ,同級別接收是前後是隨機的;級別低的收到廣播;

3 ,在 android 系統中只要監聽該廣播的接收者,都可以收到 sendBroadcast(intent) 發出的廣播 ;

 

3  ,不能截斷廣播的繼續傳播,

 

4  ,實驗現象,在這個方法發來的廣播中,代碼註冊方式中,收到的廣播的前後和註明優先級最高的他們的前後是隨機。若是都沒有優先級,代碼註冊收到爲最早。  

 

 

 

   

有序廣播的發送和接收:

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,   該廣播的級別有級別之分,級別數值是在 -10001000 之間 , 值越大 , 優先級越高;

2,   同級別接收是前後是隨機的,再到級別低的收到廣播;

3,   同級別接收是前後是隨機的,若是先接收到的把廣播截斷了,同級別的例外的接收者是沒法收到該廣播的。(  abortBroadcast()

 

4  ,能截斷廣播的繼續傳播,高級別的廣播收到該廣播後,能夠決定把該鐘廣播是否截斷掉。

5  ,實驗現象,在這個方法發來的廣播中,代碼註冊方式中,收到廣播前後次序爲:註明優先級的、代碼註冊的、沒有優先級的;若是都沒有優先級,代碼註冊收到爲最早。  

 

 

異步廣播的發送和接收:

sendStickyBroadcast(intent);

當處理完以後的Intent  ,依然存在,直到你把它去掉。

發這個廣播須要權限<uses-permission  android:name="android.permission.BROADCAST_STICKY" />  

去掉是用這個方法removeStickyBroadcast(intent);  但別忘了在執行這個方法的應用裏面 AndroidManifest.xml  一樣要加上面的權限;

 

 

sendStickyOrderedBroadcast(intent, resultReceiver,  scheduler,

       initialCode, initialData,  initialExtras)

這個方法具備有序廣播的特性也有異步廣播的特性;  

 


發送這個廣播要:  <uses-permission  android:name="android.permission.BROADCAST_STICKY" />  這個權限。才能使用這個方法。若是您並不擁有該權限,將拋出 SecurityException  的。

 

實驗現象( sendStickyOrderedBroadcast ()中),在這個方法發來的廣播中,代碼註冊方式中,收到廣播前後次序爲:註明優先級的、代碼註冊的、沒有優先級的;若是都沒有優先級,代碼註冊收到爲最早。  

 

廣播註冊與註銷

代碼中註冊廣播:

註冊廣播方法一:  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  的參數是同一參數),那麼是否當該廣播發送來的時候會收到十次呢?

 

       2  ,註銷是否也要註銷十次才能把廣播所有註銷呢?

 

系統中註冊廣播:(在 AndroidManifest.xml 中  )

< receiver android:name =  ".MyBroadcastReceiver" >

           < intent-filter android:priority = "900"  >

             

              < action  android:name  = "cn.lenovo.yangguangfu" />

           </ intent-filter >

</ receiver >

 

有時候還要根據發送廣播是否指定權限,來決定是否要權限;

 

廣播註銷

 

// 代碼中註銷廣播

/unregisterReceiver(mBatteryInfoReceiver);

 

 

 

在 Activity 中代碼註銷廣播建議在:  onPuase() 中註銷;  

不要這這裏面註銷  Activity.onSaveInstanceState(), 由於這個方法是保存  Intent 狀態的。

 

 

 

 

 

 

BroadCastReceiver 的 API

abortBroadcast ():

這個方法能夠截獲由 sendOrderedBroadcast ()  發送來的 廣播,讓其它廣播接收者沒法收到這個廣播。

clearAbortBroadcast ()

這個方法是針對上面的 abortBroadcast() 方法的,用於取消截獲廣播。這樣它的下一級廣播接收者就可以收到該廣播了。

getAbortBroadcast ()

這個方法做用是:判斷是否調用了 abortBroadcast (),若是先調用 abortBroadcast (),接着再調用 getAbortBroadcast (),將返回 true; 若是在調用 abortBroadcast() 、 clearAbortBroadcast ()

getAbortBroadcast  (),將返回 false;

 

public final boolean getDebugUnregister ()

Since: API Level 1

Return the last value given to setDebugUnregister(boolean)  .

 

 

getResultCode ()

若是用下面四個方法發送得廣播,返回碼爲: -1  ;

//  sendBroadcast(intent);

//  sendBroadcast(intent, receiverPermission);

//  sendOrderedBroadcast(intent, receiverPermission);

//  sendStickyBroadcast(intent);

若是用下面兩個方法發送得廣播,返回碼爲:根據你設置 initialCode 的數字是多少就是多少;

//  sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,

//  initialCode, initialData, initialExtras)

//  sendOrderedBroadcast(intent, receiverPermission, resultReceiver,

// scheduler, initialCode,  initialData, initialExtras)

 

 

getResultData ()

獲得發送廣播時設置的 initialData 的數據;

 

 

getResultExtras  (boolean makeMap)

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 傳入的參數。

實驗:我用上面兩個方法發了 initialExtras (這個一個 Bundle )傳入的參數時,只要不爲空,那麼  makeMap 是否爲 true 和  false 都可以獲得數據。

 

isInitialStickyBroadcast ()

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  , -  也就是說,這個值是最後的廣播出的值,目前正在舉行的宿主緩存,因此這並非直接致使瞭如今的廣播。

 

實驗:在第三個應用中調用這個方法,不管你用哪一種方式發送廣播,這個方法獲得的老是  false ;在發送廣播 的 resultReceiver 廣播接收者裏面調用,獲得的也是 false

 

 

isOrderedBroadcast ()

sendStickyOrderedBroadcast(intent, resultReceiver,  scheduler,

  initialCode, initialData,  initialExtras)

上面這個方法發送時,獲得的是 true;

判斷是不是有序廣播;

 

 

onReceive (Context context, Intent intent)

 

public IBinder peekService (Context myContext, Intent service)  

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.

setDebugUnregister (boolean debug)

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

相關文章
相關標籤/搜索