BroadcastReceiver详解(基础篇)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BroadcastReceiver详解(基础篇)相关的知识,希望对你有一定的参考价值。

参考技术A

Broadcast (广播)是一种广泛运用的应用程序之间传输信息的机制,而 BroadcastReceiver (广播接收器)则是用于接收来自系统和应用的广播对并对其进行响应的组件,android中我们要发送的广播内容是一个 Intent ,这个 Intent 中可以携带我们要传送的数据

创建一个广播接收器非常简单,只需要继承 BroadcastReceiver ,并重写 onReceive() 即可

BroadcastReceiver 也是四大组件之一,所以我们也需要对 BroadcastReceiver 进行注册,不同于其他四大组件, BroadcastReceiver 有两种注册方式,分别是 静态注册 动态注册

静态注册

当我们的应用首次启动的时候,系统会自动实例化我们静态注册的 BroadcastReceiver ,然后将这个 BroadcastReceiver 注册到系统中,系统接收到广播之后,就会做出相应的判断,调用 onReceive() 方法。通过这种方式注册的广播,即使我们的应用被销毁,依然能收到广播。 这里要注意的是,我们的应用一定要被启动过 ,如果没有被启动可能就无法接收到广播,可以参考文章 Android应用在未启动的情况下无法收到指定广播的问题总结

正是因为静态注册耗电、占内存、不受程序生命周期影响,所以Google在Android 8.0上禁止大部分广播的静态注册,可以参考官文文档 Android 8.0 功能和 API

动态注册

通过动态注册的广播, BroadcastReceiver 的生命周期跟随Activity的生命周期

注意: 要在 Activity 的 onPause() 中 unRegeisterReceiver() ,否则会引起内存泄漏。比较推荐 onResume() 中去注册广播,在 onPause() 中去注销广播。因为在内存资源比较吃紧的情况下,可能我们的 Activity 执行完 onPause() 之后就被销毁,这时候 Activity 的 onStop() 和 onDestory() 方法就不会执行了

BroadcastReceiver注册完之后,这个 BroadcastReceiver 就能够接收响应的广播,下面我们来说说如何发送一条广播

普通广播(Normal Broadcast)

普通广播完全是异步的,通过 context.sendBroadcast() 方法发送,消息传递效率比较高,但所有接收器的执行顺序不确定。缺点是接收者不能将处理结果传递给下一个接收者,并且无法终止广播的传播

有序广播(Ordered Broadcast)

有序广播是通过 context.sendOrderedBroadcast() 方法发送,所有的广播者按照优先级依次执行,广播接收器的优先级通过 receiver 的 intent-filter 中的 android:priority 属性来设置,数值越大优先级越高。当广播接收器接收到广播后,可以使用 setResult() 方法把结果传递给下一个接收者,通过 getResult() 方法获取上一个接收者传递过来的结果,并可以通过 abortBroadcast() 方法丢弃该广播,使该广播不再传递给下一个接收者

粘性广播(Sticky Broadcast)

粘性广播通过 context.sendStickBroadcast() 方法来发送,用此方法发送的广播会一直滞留,当有匹配此广播的接收器被注册后,该广播接收器就会收到此广播。使用此广播时,需要获得 BROADCAST_STICKY 权限

由于在Android5.0 & API 21中已经失效,所以不建议使用。

本地广播(Local Broadcast)

前三种广播都是全局广播,所有应用都可以接收到,这样就带来安全隐患,而本地广播只在进程内传播,可以起到保护数据安全的作用

其实,本地广播的使用与其十分类似,之前的步骤均是一样的,调用者不同而已,本地广播调用的是 LocalBroadcastManager 相关方法,全局广播调用的是 Context 的相关方法,其方法名都是一样的

这里需要说一下, 使用本地广播并没有静态注册的方法 ,因为静态注册主要是为了让程序在未启动的情况下也能收到广播,而发动本地广播的时候,我们的程序已经是启动了,所以,自然是没有静态注册这个方法

Android中内置了多个系统广播,当使用系统广播时,只需要在注册广播接收者时定义相关的 action 即可,并不需要手动发送广播,当系统有相关操作(如开机、网络状态变化、拍照等等)时会自动进行系统广播

Android系统广播 action 如下:

本文介绍了 BroadcastReceiver 的两种注册方式(动态注册、静态注册),四种发送方式(普通广播、有序广播、粘性广播(API21废弃)、本地广播),以及系统广播的用法。几乎涵盖了 BoradcastReceiver 在应用开发过程中的所有知识,对于BroadcastReceiver原理感兴趣的可以继续看 BroadcastReceiver详解(原理篇)

Android中广播接收者BroadcastReceiver详解

1. 接收系统的广播步骤

 

(1)  新建一个类继承BroadcastReceiver

 

以监听sd卡状态的广播接收者为例

 1 public class SdCardBroadcastReceiver extends BroadcastReceiver {
 2 
 3     @Override
 4     public void onReceive(Context context, Intent intent) {
 5         String action = intent.getAction();
 6         if("android.intent.action.MEDIA_MOUNTED".equals(action)){
 7             System.out.println("sd卡已挂载");
 8         }else if("android.intent.action.MEDIA_UNMOUNTED".equals(action)){
 9             System.out.println("sd卡已卸载");
10         }
11     }
12 
13 }

 

形象一点的比喻, 这一步相当于买了个收音机

 

(2) 在清单文件中注册

 

1 <!-- 相当于装电池 -->
2         <receiver android:name="com.example.sdbroadcast.SdCardBroadcastReceiver">
3             <!-- 相当于调频道 -->
4             <intent-filter>
5                 <action android:name="android.intent.action.MEDIA_MOUNTED"/>
6                 <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
7                 <data android:scheme="file"/>
8             </intent-filter>
9         </receiver>

 

这一步相当于装电池

 

(3)  在清单文件中添加意图过滤器,action里写监听的内容

 

1  <!-- 相当于调频道 -->
2             <intent-filter>
3                 <action android:name="android.intent.action.MEDIA_MOUNTED"/>
4                 <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
5                 <data android:scheme="file"/>
6             </intent-filter>

 

这一步相当于调频道了

 

2. 发送自定义的无序广播

 

(1) 发送广播

 

 1 public void startBroadcast(View view){
 2         //开启广播
 3         //创建一个意图对象
 4         Intent intent = new Intent();
 5         //指定发送广播的频道
 6         intent.setAction("com.example.BROADCAST");
 7         //发送广播的数据
 8         intent.putExtra("key", "发送无序广播,顺便传递的数据");
 9         //发送
10         sendBroadcast(intent);
11     }

 

(2) 接收广播

 

新建一个类,继承BroadcastReceiver

 

 1 public class UnorderedReceiver extends BroadcastReceiver {
 2 
 3     @Override
 4     public void onReceive(Context context, Intent intent) {
 5         String action = intent.getAction();
 6         
 7         String data = intent.getStringExtra("key");
 8         
 9         System.out.println("接受到了广播,action:"+ action +",data:"+data);
10         
11         //接受到了广播,action:com.example.BROADCAST,data:发送无序广播,顺便传递的数据
12     }
13 
14 }

 

记得在清单文件中进行注册

 

1 <receiver android:name="com.example.selfreceiver.UnorderedReceiver">
2             <intent-filter>
3                 <action android:name="com.example.BROADCAST"/>
4             </intent-filter>
5         </receiver>

 

打印出的结果:

 

技术分享

 

3. 发送自定义的有序广播

(1) 发送广播

 1 // 发送有序广播
 2     public void sendOrderedBroad(View view) {
 3         Intent intent = new Intent();
 4         intent.setAction("com.example.ORDERED");
 5         // 发送无序广播
 6         sendOrderedBroadcast(intent,//意图动作,指定action动作
 7                 null, //receiverPermission,接收这条广播具备什么权限
 8                 new FinalReceiver(),//resultReceiver,最终的广播接受者,广播一定会传给他
 9                 null, //scheduler,handler对象处理广播的分发
10                 0,//initialCode,初始代码
11                 "每人发10斤大米,不得有误!", //initialData,初始数据
12                 null//initialExtras,额外的数据,如果觉得初始数据不够,可以通过bundle来指定其他数据
13                 );
14     }

 

在上面的代码中,广播发送者发送了一条广播:"每人发10斤大米,不得有误!"

 

(2) 接收广播

 

新建一个类, 继承BroadcastReceiver,并在清单文件中进行注册

以下是所有的广播接收者在清单文件中的注册

 

技术分享

 

权限从-1000 至 1000

 

1) 权限高的广播接收者可以修改广播,甚至可以终止广播

 

权限高的广播接收者1:

 

 1 public class ShengReceiver extends BroadcastReceiver {
 2 
 3     @Override
 4     public void onReceive(Context context, Intent intent) {
 5         
 6         //获取广播的数据
 7         String data = getResultData();
 8         
 9         //修改
10         setResultData("中央下达福利,每人5斤大米");
11         
12         System.out.println("省政府收到指示, data : "+data);
13     }
14 
15 }

 

在这里, 这个接收者修改广播为: "中央下达福利,每人5斤大米"

 

权限低的广播接收者

 

 1 public class PeopleReceiver extends BroadcastReceiver {
 2 
 3     @Override
 4     public void onReceive(Context context, Intent intent) {
 5         //获取广播的数据
 6         String data = getResultData();
 7         System.out.println("老百姓收到福利,感谢党, data : "+data);
 8     }
 9 
10 }

 

这样,在控制台打印出来的信息为:

 

技术分享

 

权限低的接收者 接收到的广播就是修改后的了

 

2) 终止广播

 

权限高的广播接收者:

 

 1 public class ShengReceiver extends BroadcastReceiver {
 2 
 3     @Override
 4     public void onReceive(Context context, Intent intent) {
 5         
 6         //获取广播的数据
 7         String data = getResultData();
 8         
 9         //也可以终止广播,权限小的接收者就接收不到广播了
10         abortBroadcast();
11         
12         System.out.println("省政府收到指示, data : "+data);
13     }
14 
15 }

 

控制台打印:

技术分享

 

权限小的就接收不到广播了....

 

(3) resultReceiver

 

可以在广播发送者的应用中建一个resultReceiver, 用于接收最终到达的广播,

无论广播是否终止,都会被resultReceiver接收

 

1 public class FinalReceiver extends BroadcastReceiver {
2 
3     @Override
4     public void onReceive(Context context, Intent intent) {
5         String resultData = getResultData();
6         System.out.println("人民收到的最终福利是: "+ resultData);
7     }
8 
9 }

 

控制台打印信息:

 

(终止广播后):

技术分享

(修改广播后):

技术分享

 

4. 补充:

有序广播和无序广播的区别:

 

有序广播:发送方发出后,几乎同时到达多个广播接收者处,某个接收者不能接收到广播后进行一番处理后传给下一个接收者,并且无法终止广播继续传播;Context.sendBroadcast(intent);

有序广播:广播接收者需要提前设置优先级,优先级高的先接收到广播,优先级数值为-1000~1000,在AndroidManifest.xml的<intent-filter android:priority="xxx">设置;比如存在3个广播接收者A、B、C,优先级A>B>C,因此A最先收到广播,当A收到广播后,可以向广播中添加一些数据给下一个接收者(intent.putExtra()),或者终止广播(abortBroadcast());Context.sendOrderedBroadcast(intent);

 

以上是关于BroadcastReceiver详解(基础篇)的主要内容,如果未能解决你的问题,请参考以下文章

Android基础篇 静态注册 and 动态注册 BroadcastReceiver系列

Android基础&进阶

BSGS(基础篇,题目+详解)

[ 基础漏洞篇 ] webpack 前端源码泄露详解

BroadcastReceiver应用详解——广播

Android-BroadcastReceiver详解及实例