摘要:該文章介紹了LocalBroadManager和BroadcastReceiver,講解如何使用本地廣播,如何監聽系統廣播,如何創建具有自定義權限的廣播,發送廣播的方式等。
============================================
文章結構
1. BroadcastReceiver介紹
1.1 不跨進程的廣播LocalBroadcastManager:
1.2 BroadcastReceiver:
1.2.2 自定義權限的BroadcastReceiver
1.2.3 利用廣播開啓服務
============================================
1. BroadcastReceiver介紹
個人理解: BroadcastReceiver是安卓的四大組件之一,有接受廣播機制,相對應就有發送廣播機制。安卓下,通過該機制,使得消息能在各個組件間、各個進程間傳遞,起到郵遞員的作用。
1.1 不跨進程的廣播LocalBroadcastManager:
當我們發送的廣播不需要跨應用發送時,我們可以使用LocalBroadcastManager,關於它,官網API的描述是:
Class Overview
Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent)
:
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.
It is more efficient than sending a global broadcast through the system.
意思是:它是一個Helper,能幫忙註冊廣播接收者,而且提供發送給本進程的對象的方法。相比於發送全局廣播的sendBroadcast有很多優點。其體現在:1、廣播的數據不會離開本身的進程,所以不用擔心泄露私人數據;2、其他應用程序不可能發廣播給你的應用,所以不用擔心有安全漏洞會被利用;3、相比於經過系統的全局廣播更有效率。
個人觀點:通過線程內的通信用Handler會更方便,所以這種LocalBroadcastManager也是比較少用,不過相比於Handler,LocalBroadcastManager的優勢在於如果在通過線程內,多個對象要收到消息,LocalBroadcastReceiver發一次,而Handler則要發多次。LocalBroadcastManager的使用方法是:
1、建立一個類,該類沒有構造方法,要通過該對象的靜態方法getInstance()方法來獲取LocalBroadcastManager對象;
2、獲取對象後,可以利用該對象建立一個BroadcastReceiver或是利用該對象來發送廣播。
1.2 BroadcastReceiver:
當需要發送能夠跨線程、跨進程的廣播時,就可以使用BroadcastReceiver了。它接受的對象是Intent,Intent可以攜帶Action,也可以攜帶數據等。每一個BroadcastReceiver都需要建立一個Intent-filter,不然就無法過濾不想收到的Intent對象。而當某個線程想發一個廣播給某個廣播接收器時,發送的Intent的Action必須符合該廣播接收器的Intent-filter的Action,不然無法接收。
它的使用思路是:
(1)建立一個繼承BroadcastReceiver的類 ,實現onReceive方法(收到廣播後回調的函數);
(2)在Manifest.xml文件註冊,註冊時要設置Intent-filter,也可在Intent-filter設置其優先級,可在Receiver標籤設置permission屬性(一般是自定義BroadcastReceiver時用到)。
1.2.1 監聽系統功能的BroadcastReceiver
BroadcastReceiver可以監聽任何廣播,包括系統廣播,只要把Intent-filter設置成相對應的Action則可以收到。安卓系統很多操作都會發出廣播,比如撥打電話,他是發送一個Intent給系統的廣播接收者,有系統的廣播接收者去調用撥號服務,相對應的Action是android.action.NEW_OUTGOING_CALL,當然監聽系統的廣播是需要權限的,這個用到的權限是android.permission.PROCESS_OUTGOING_CALLS。
下面以監聽系統的撥號廣播爲例:
(1)建立廣播接收者:
1 2 3 4 5 6 7 8 9 10 11 | public class ListenDial extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String num = getResultData();
Log.i( "cth" , "監聽到撥打電話信息,撥打號碼爲:" + num);
//監聽用戶撥打的電話,可獲取號碼或更改撥號的號碼。
//需要的權限是android.permission.PROCESS_OUTGOING_CALL
//該receiver的Intent-filter的action必須設爲android.action.NEW_OUTGOING_CALL
} } |
(2)在Manifest.xml文件的註冊:
1 2 3 4 5 6 7 8 9 | <!-- 使用系統權限 -->
<uses-permission android:name= "android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 註冊該接收器,設置Intent-filter --> <receiver android:name= ".ListenDial" >
<intent-filter>
<action android:name= "android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter> </receiver> |
當系統有撥號的時候,我們這個廣播接收器就可以收到撥號廣播,並獲取撥號號碼。同理,只要監聽相對應的系統廣播,都可以獲得廣播裏面的數據,比如接收短信等。
1.2.2 自定義權限的BroadcastReceiver
系統的廣播有它自己的權限,我們只要知道它的權限就可以進行監聽。同樣地,我們也可以自定義具有自己權限的廣播接收者,建立自己的發送接受廣播機制。
實現步驟如下:
(1)建立一個繼承BroadcastReceiver的類,實現onReceive方法;
(2)在Manifest聲明一個權限,用<permission></permission>,並使用該權限,用<uses-permission />;
(3)註冊Receiver元素,添加Intent-filter以及其Action(添加權限和優先級自選);
(4)在Activity中用sendBroadcast或sendOrderedBroadcast發送廣播,廣播攜帶的Intent的action符合自定義的permission標籤的name屬性則可被收到。
例子:
建立三個廣播接收者,分別有不同的優先級,和權限,但是他們的Intent-filter的Action都相同。先發送一個不帶權限的廣播且符合三者的Action,三者都收到,因爲優先級不同,收到的順序也不同,優先級越高越快收到。接下來發送帶要驗證權限,發送帶權限的廣播,只有符合權限的才收到。再建立一個FinalReceiver,發送帶FinalReceiver的廣播,在FinalReceiver收到中止廣播,結果FinalReceiver還是收到了。
(1)建立三個廣播接收者的Java代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | public class DIYBR1 extends BroadcastReceiver {
/*
* 定義一個廣播接收者,監聽的行爲cth.android.DIYBR,收到後終端廣播。
* 它需要在Manifest註冊,name和Intent-filter都需要設置,
* 權限和優先級可選設置。
* <receiver
android:name=".DIYBR1"
android:permission="cth.authority" >
<intent-filter android:priority="100" >
<action android:name="cth.android.DIYBR" />
</intent-filter>
</receiver>
*
* */
@Override
public void onReceive(Context arg0, Intent arg1) {
if (arg1.getAction() == "cth.android.DIYBR" ) {
Log.i( "cth" , "DIYBR1接收到" );
abortBroadcast(); //中止廣播
}
} }
public class DIYBR2 extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
if (arg1.getAction() == "cth.android.DIYBR" ) {
Log.i( "cth" , "DIYBR2接收到" );
}
}
}
public class DIYBR3 extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
if (arg1.getAction() == "cth.android.DIYBR" ) {
Log.i( "cth" , "DIYBR3接收到" );
}
}
} |
(2)在Manifest註冊三個廣播接收者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | < receiver
android:name = ".DIYBR1"
android:permission = "cth.authority" >
< intent-filter android:priority = "100" >
< action android:name = "cth.android.DIYBR" />
</ intent-filter >
</ receiver >
< receiver android:name = ".DIYBR2"
android:permission = "null" >
< intent-filter android:priority = "1000" >
< action android:name = "cth.android.DIYBR" />
</ intent-filter >
</ receiver >
< receiver android:name = ".DIYBR3"
android:permission = "null" >
< intent-filter android:priority = "10" >
< action android:name = "cth.android.DIYBR" />
</ intent-filter >
</ receiver > |
(3)另外開一個工程發送廣播,這樣除了驗證上述結果,還可以做到驗證可以跨進程發送:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction( "cth.android.DIYBR" ); //設置Action
//發送不帶權限的廣播,在清單文件中Intent-filter的action的name值符合該Action的能收到。
sendBroadcast(intent); //直接發送一個無權限的廣播
//發送一個規定權限的廣播,只有持有該權限的廣播接受者才能收到該廣播
sendOrderedBroadcast(intent, "cth.authority" );
//發送一個規定權限和最終廣播接受者的廣播,
//當第三個參數規定了resultRecevier,則表示該廣播發出,該resultRecevier一定會接收到,
//不管它的優先級是怎麼樣的,不管廣播是否中途被中斷,不管它是否符合第二個參數所規定的權限。
sendOrderedBroadcast(intent, "cth.authority" , new FinalBR(),
null , 0 , null , null );
//注意:自定義的權限在Manifest要用<permission />聲明,而且要<uses-permission />使用
}
}); |
(4)結果:
發送不帶權限的廣播:
因爲DIYBR1優先級比DIYBR2和DIYBR3高,DIYBR1中止了廣播,所以DIYBR2和DIYBR3收不到,但是FinalBR是跟發送廣播同進程,所以可以收到,即使它的優先級比DIYBR1低也不會受影響。所以證明abortBroadcast只能中止本進程的廣播,發到其他進程的中止不了。
發送帶權限的廣播:
這個時候就只有符合權限的DIYBR1才能收到。
發送一個規定權限和最終廣播接受者的廣播:
可以看到只有權限符合的DIYBR1才能收到,而FinalReceiver權限不符合也能收到,這裏還有說明一點,FinalReceiver即使廣播之前被優先級高的中止了還是能收到。
1.2.3 利用廣播開啓服務
我們開啓服務一般是startService或是bindService,但是有時候我們也可以通過服務內部提供的廣播來開啓服務並獲取服務的方法。注意:BroadcastReceiver是四大組件唯一一個可以動態註冊的!
操作步驟如下:
(1)建立一個繼承Service的類並在Manifest.xml註冊,該類內部定義一個繼承BroadcastReceiver的內部類,在其onReceive使用Service的方法;
(2)在服務的onCreate方法實例化該BroadcastReceiver子類,並使用registerReceiver來註冊該BroadcastReceiver對象,添加Intent-filter;
(3)新建一個Activity,發送符合(2)中廣播接收者Action的廣播,如果(2)中的廣播接收到符合的Intent的廣播,則會執行onReceive中服務的方法。
具體代碼如下:
(1)包含BroadcastReceiver內部類的Service類:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | package cth.android.BRopenService;
import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; import android.util.Log; import android.widget.Toast;
public class MyService extends Service {
private ServiceCR receiver;
@Override
public IBinder onBind(Intent arg0) {
return null ;
}
@Override
public void onCreate() {
Log.i( "cth" , "服務創建" );
IntentFilter filter = new IntentFilter();
filter.addAction( "cth.android.BRopenService" ); //爲Intent-filter添加Action
receiver = new ServiceCR();
registerReceiver(receiver, filter); //動態註冊廣播
Log.i( "cth" , "廣播接收器已註冊" );
super .onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i( "cth" , "服務創建" );
return super .onStartCommand(intent, flags, startId);
}
private void openService () {
Toast.makeText(getApplicationContext(), "服務已開啓" ,Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
super .onDestroy();
unregisterReceiver(receiver); //取消廣播的註冊
}
private class ServiceCR extends BroadcastReceiver { //服務中定義廣播接收者的內部類
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getAction() == "cth.android.BRopenService" ) {
Log.i( "cth" , "接收到廣播" );
openService(); //使用服務中的方法
}
}
}
} |
(2)發送廣播的Activity:
1 2 3 4 5 6 7 8 9 10 | button = (Button) findViewById(R.id.button);
button.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction( "cth.android.BRopenService" ); //發送符合Service中BroadcastReceiverAction的廣播
sendBroadcast(intent);
}
}); |
(3)結果:
可以看見發送一個廣播就可以調用服務內部openService這個方法,相當於開啓了服務。