BroadcastReceiver总结

本文转自http://cthhqu.blog.51cto.com/7598297/1282534

摘要:该文章介绍了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
publicclassListenDial extendsBroadcastReceiver {
@Override
publicvoidonReceive(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
publicclassDIYBR1 extendsBroadcastReceiver {
/*
* 定义一个广播接收者,监听的行为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
publicvoidonReceive(Context arg0, Intent arg1) {
if(arg1.getAction() == "cth.android.DIYBR") {
Log.i("cth","DIYBR1接收到");
abortBroadcast();  //中止广播
}
}
}
publicclassDIYBR2 extendsBroadcastReceiver {
@Override
publicvoidonReceive(Context arg0, Intent arg1) {
if(arg1.getAction() == "cth.android.DIYBR") {
Log.i("cth","DIYBR2接收到");
}
}
}
publicclassDIYBR3 extendsBroadcastReceiver {
@Override
publicvoidonReceive(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-filterandroid:priority="100">
<actionandroid:name="cth.android.DIYBR"/>
</intent-filter>
</receiver>
<receiverandroid:name=".DIYBR2"
android:permission="null">
<intent-filterandroid:priority="1000">
<actionandroid:name="cth.android.DIYBR"/>
</intent-filter>
</receiver>
<receiverandroid:name=".DIYBR3"
android:permission="null">
<intent-filterandroid:priority="10">
<actionandroid: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(newOnClickListener() {
@Override
publicvoidonClick(View v) {
Intent intent = newIntent();
intent.setAction("cth.android.DIYBR"); //设置Action  
//发送不带权限的广播,在清单文件中Intent-filter的action的name值符合该Action的能收到。
sendBroadcast(intent); //直接发送一个无权限的广播
//发送一个规定权限的广播,只有持有该权限的广播接受者才能收到该广播
sendOrderedBroadcast(intent, "cth.authority");  
//发送一个规定权限和最终广播接受者的广播,
//当第三个参数规定了resultRecevier,则表示该广播发出,该resultRecevier一定会接收到,
//不管它的优先级是怎么样的,不管广播是否中途被中断,不管它是否符合第二个参数所规定的权限。
sendOrderedBroadcast(intent, "cth.authority"newFinalBR(),
null0nullnull);
//注意:自定义的权限在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
packagecth.android.BRopenService;
importandroid.app.Service;
importandroid.content.BroadcastReceiver;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.IntentFilter;
importandroid.os.IBinder;
importandroid.util.Log;
importandroid.widget.Toast;
publicclassMyService extendsService {
privateServiceCR receiver;
@Override
publicIBinder onBind(Intent arg0) {
returnnull;
}
@Override
publicvoidonCreate() {
Log.i("cth","服务创建");
IntentFilter filter = newIntentFilter();  
filter.addAction("cth.android.BRopenService");  //为Intent-filter添加Action
receiver = newServiceCR();
registerReceiver(receiver, filter);  //动态注册广播
Log.i("cth","广播接收器已注册");
super.onCreate();
}
@Override
publicintonStartCommand(Intent intent, intflags, intstartId) {
Log.i("cth","服务创建");
returnsuper.onStartCommand(intent, flags, startId);
}
privatevoidopenService () {
Toast.makeText(getApplicationContext(),"服务已开启",Toast.LENGTH_SHORT).show();
}
@Override
publicvoidonDestroy() {
super.onDestroy();
unregisterReceiver(receiver); //取消广播的注册
}
privateclassServiceCR extendsBroadcastReceiver {  //服务中定义广播接收者的内部类
@Override
publicvoidonReceive(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(newOnClickListener() {
@Override
publicvoidonClick(View v) {
Intent intent = newIntent();
intent.setAction("cth.android.BRopenService"); //发送符合Service中BroadcastReceiverAction的广播
sendBroadcast(intent);
}
});
(3)结果:

可以看见发送一个广播就可以调用服务内部openService这个方法,相当于开启了服务。

原文地址:https://www.cnblogs.com/lemonhome/p/4492625.html