Android中BroadcastReceiver的介紹


本文主要簡單的討論下Android中廣播發送與注冊的多種方式

注冊廣播接收者有兩種方式,動態與靜態:

1,動態注冊:在Activity的onCreate方法中或根據需要調用register()方法注冊即可動態注冊一個廣播接收者,在代碼中有關於其特點的簡單注釋,如下

private void register() {
ReceiverTool rt = new ReceiverTool();
IntentFilter filter = new IntentFilter();
filter.addAction("com.xiaomo.view.broadcast01");
registerReceiver(rt, filter);
}

/**
* 動態注冊 -- 接收廣播
* 每次接收廣播使用的是同一個接收實例,並不會每次都創建一個實例
*
@author Administrator
*
*/
class ReceiverTool extends BroadcastReceiver {

public ReceiverTool () {
// Log.i(Constant.TAG, "創建了ReceiverTool的一個實例");
}

@Override
public void onReceive(Context context, Intent intent) {
Log.i(Constant.TAG, "" + this.hashCode());
Log.i(Constant.TAG, "接到到廣播, ACTION = " + intent.getAction());
}
}

2,靜態注冊,自定義一個class extends BroadcastReceiver,然后在mainfest.xml中使用<receiver...>標簽的形式注冊,特性同樣注釋在代碼中:

/**
* 靜態注冊(mainfest.xml) -- 接收廣播
* 每次接收到相應的廣播,都會創建一個接收器的實例,這一點與動態注冊不同
* 之所以這樣設計,個人認為實屬無奈,因為在mainfest.xml中注冊了一個接收者,相當於一個標記
* 但系統無法知道什么時候會接收到對應的廣播
* 1,系統在掃描到配置文件中注冊了接收者時,就為其創建對象 (不知道什么時候會接收到廣播)
* 2,系統在該接收者接收到廣播時,第一次為其創建對象 (不知道什么時候會再次接收到廣播)
* 如果這兩種情況下,都在內存中保存這個接收者對象,那么就會出現對應的括號中場景
* 並且一直保存在內存中,明顯占內存,浪費內存資源(一個接收者無關緊要,但若一個應用中有10, 100..個靜態廣播接收者,你懂的!)
* 所以不能采用這樣的設計,而采用每次接收到廣播,就為其創建對象,用完就清掉
* 而且在處理接收廣播過程中,Android還加上了超時限制(ANR異常,因為BroadcastReceiver默認運行在UI主線程中)
*
@author Administrator
*
*/
public class StaticReceiverTool extends BroadcastReceiver{

public StaticReceiverTool() {
// Log.i(Constant.TAG, "創建了StaticReceiverTool的一個實例");
}
@Override
public void onReceive(Context context, Intent intent) {

// Log.i(Constant.TAG, "" + this.hashCode());
Log.i(Constant.TAG, "StaticReceiverTool接到到廣播, ACTION = " + intent.getAction());


}
}

mainfest.xml:

<receiver android:name="com.xiaomo.view.broadcast.StaticReceiverTool">
<intent-filter>
<action android:name="com.xiaomo.view.broadcast01"></action>
</intent-filter>
</receiver>

 

廣播接收者可以接收系統自帶的廣播,也可以接收自定義的廣播

那么相應的,Intent中的action可以自定義也可以是使用系統相應服務特定的action

自定義的廣播發送方式一般如下:

Intent intent = new Intent("com.xiaomo.view.broadcast01");
sendBroadcast(intent);
// sendBroadcast(intent);連續發送兩次,那么接收者就會連續接收兩次同樣的廣播


對於多個廣播接收者接收同一個廣播,會涉及到優先級priority的概念,下面再定義一個broadcastReceiver(動態與靜態的區別上面已經說過,這里采用靜態的方式):

public class StaticReceiverTool02 extends BroadcastReceiver {


public StaticReceiverTool02() {
}

@Override
public void onReceive(Context context, Intent intent) {
Log.i(Constant.TAG,
"StaticReceiverTool02接到到廣播, ACTION = " + intent.getAction());

// 接收non-ordered廣播時,如果調用方法終止廣播
// 會報異常:BroadcastReceiver trying to return result during a non-ordered
// broadcast
// this.abortBroadcast();


}

其對應的xml中得配置:

<receiver android:name="com.xiaomo.view.broadcast.StaticReceiverTool02">
<intent-filter android:priority="10">
<action android:name="com.xiaomo.view.broadcast01"></action>
</intent-filter>
</receiver>

注意StaticReceiverTool02這個receiver的配置中加了優先級android:priority="10",那么使用上面的代碼發送廣播后,Log中的狀態為:

StaticReceiverTool02接到到廣播, ACTION = com.xiaomo.view.broadcast01

StaticReceiverTool接到到廣播, ACTION = com.xiaomo.view.broadcast01

因為StaticReceiverTool02的優先級priority = 10 比StaticReceiverTool的0高(如果不加優先級設置,兩者幾乎同時收到廣播,沒有固定的順序)

在android系統中默認的優先級 = 0, 優先級的范圍為-1000 ~ 1000,最高的優先級為1000.


如果想終止廣播,可以調用abortBroadcast();方法,但上面的示例中無論在哪個接收者中調用,都會出現異常(見code注釋),這涉及到android系統中幾種不同的廣播發送方式,而若使用上面代碼中的發送方式sendBroadcast(intent),則接收者在處理過程中是不能終止廣播的繼續傳遞的,這個在源碼中明確說明。

 

接下來討論下廣播的幾種發送方式:

1, 就是上面說到的常用方式:sendBroadcast(intent);


2, 有序廣播 sendOrderedBroadcast(intent, "com.xiaomo");  (有序的廣播可以使用abortBroadcast()終止廣播)

第二個參數為權限控制,無權限就寫null即可

當然若加了權限,則必須在maifest.xml中申明權限且設置接收權限

<uses-permission android:name="com.xiaomo" />

<permission android:name="com.xiaomo" android:protectionLevel="normal"></permission>

這樣才可以接收到廣播,此時若在StaticReceiverTool02的onReceiver()中加入代碼this.abortBroadcast();

那么StaticReceiverTool就接收不到這個廣播了.

 

3,sendStickyBroadcast(intent);

這個不涉及到自定義權限,但是需要在配置文件中設置使用權限:<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

這種方式也同樣不能在接收過程中,終止廣播.

這種方式的特殊之處在於,廣播發送出去后,即使沒有對應的接收者,內存中也會緩存這個廣播,在未刪除之前,一旦有相應的接收者注冊,那么這個接收者就會收到這個廣播

還使用上面的例子,把action改一下即可(此段代碼在activity的oncreate(...)中):

new Handler().postDelayed(new Runnable() {
@Override
public void run() {
register();
}
}, 30000);

// new Handler().postDelayed(new Runnable() {
// @Override
// public void run() {
//
// register();
// }
// }, 20000);

Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.xiaomo.view.broadcast02");
sendStickyBroadcast(intent);
Log.i(Constant.TAG, "廣播發送完畢");
}
});

把上面register()方法中action的string值改成對應的02(額,主要是不想動配置文件了,不然好幾個接收者接收同一個廣播,對比的不清楚)

filter.addAction("com.xiaomo.view.broadcast02");

運行后,先點擊button發送廣播,可以發現log中只顯示了“廣播發送完畢”,等待大約30秒后,會顯示“接收到廣播。。。。”

即通過sendStickyBroadcast(intent)發送的廣播先緩存在內存中,30秒后子線程執行注冊廣播接收者的代碼,然后這個接收者就會立即接收到...broadcast02這個廣播

當然也可以從內存中將這個緩存的廣播刪除:

@Override
public void onReceive(Context context, Intent intent) {
removeStickyBroadcast(intent);//刪除在內存中的廣播
Log.i(Constant.TAG, "" + this.hashCode());
Log.i(Constant.TAG, "接到到廣播, ACTION = " + intent.getAction());
}

這樣其他可以接收到這個廣播的接收者就不會接收到這個廣播了(當然當前的receiver得比其他receiver先接收到這個廣播, 順序問題又涉及到上面的有序/無序,優先級的問題了)

 

4,還有一種比較蛋疼的方式:sendStickyOrderedBroadcast(Intent intent,

BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras)

。。。哈哈,好吧,我承認,這個我看了一眼,就沒看過第二眼(當然也從來沒見過哪里使用這種方式發送廣播的....)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM