Android 笔记:"BroadcastReceiver"

1 是什么
2 怎么用
3 两种注册方式
4 两种类型
5 生命周期
6 注意事项
复制代码

前言


BroadcastReceiver是什么? --- 广播(通知消息)接收器

在Android的API中说道,他是一个基类,让程序(这里的程序不是只整个应用程序,而是我们的代码片段,也就是具有独立功能的代码)可以接收到由Context.sendBroadcast()发送过来的intents

BroadcastReceiver是 Android四大组件之一。系统中有许多广播,例如: 通知时间改变 电池电量改变 拍摄了照片 改变了语言 等等...,这些系统操作完后都会发送一个全局的广播,所有应用都可以接收到。

BroadcastReceiver和Service一样,是木有用户界面的。

BroadcastReceiver的存在,降低程序间的耦合,只需要一个接收器,就可以接收程序间发出的消息。

知识点


怎么用

想要使用Broadcast,我们需要两个东西。一个是Broadcast的发出者,一个是接收者。接收者肯定是本篇笔记的主角BroadcastReceiver。发出者发送Broadcast需要使用Context.sendBroadcast()。所以一般情况下,可以是Activity作为发出者,Service也可以作为发出者,因为他们均继承自Context。我们只需要在Activity或Service中调用sendBroadcast()方法即可。而接收者则需要定义一个类,并继承自BroadcastReceiver。下面来看看具体如何实现吧。

创建一个我们的广播接收器 extends BrocastReceiver

先来实现广播接收者。 从BrocastReceiver的类可以看出,它是一个抽象类,不能实例化对象,则我们需要定义一个类去继承它,并实现里面的抽象方法 onReceiver(context,intent)

至此,一个简单的广播接收者BroadcastReceiver就算是完成了,我们只需要在 onReceive()方法里面添加处理逻辑即可。

广播接收机器BroadcastReceiver的类完成之后,我们要怎么才能让他可以接收到Broadcast呢?跟Service和Activity一样,Android四大组件的使用都需要注册,让系统知到我们的Application里面有这些大家伙的存在。

注册广播接收器的2种注册形式:

  • 静态 : Manifest.xml

和Activity、Service一样,我们可以在AndroidManifest.xml文件中进行静态的注册。不同的是,BroadcastReceiver也可以不在Manifest中注册,而是通过在代码中动态注册,下文会具体阐述。

静态注册的特点是:对于广播的接收和程序是否启动无关。

  • 动态: 动态注册,顾名思义,肯定是通过代码来实现的。动态注册需要用到以下内容:
1 意图过滤器 IntentFilter 用于给BroadcastReceiver绑定监听广播类型
2 自定义的BroadcastReceiver,例如上文的MyBroadcastReceiver
3 注册方法 Context.registerReceiver(Receiver, IntentFilter)
4 反注册方法 unregisterReceiver(Receiver);
复制代码

我们需要在Activity中创建一个IntentFilter用来添加一个Action,该Action是我们期望监听的广播类型,当要监听系统广播时,使用系统给我们提供的action,监听定义的广播类型,则可以自行定义Action值。事实上,Broadcast发送传递给BroadcastReceiver的实际上是一个Intent。我们再BroadcastReceiver的onReceive中通过判断intent的action就可以识别该广播是否为我们所需要的。 然后把广播接收器的对象和设置好action的IntentFilter对象传给Context.registReceiver()方法进行注册。 这样我们就得到一个可以监听Action所指定的类型的广播的广播接收器了。

下面是一个注册与反注册BroadcastReceiver的例子,也是Google API推荐的做法,在activity的onResume()中注册,在onPause()反注册。效果是当界面pause时,就不接收广播,从而减少不必要的系统开销。

静态注册与动态注册的区别?

动态注册可以反注册,主要是适用于广播接收器与界面的生命周期绑定的情况。 在onStart中注册 registerReceiver(receiver,intentfilter) 在onStop中反注册 unregistReceiver

我在android的api文档中看到,说在activity的onResume()中注册,在onPause()反注册 效果是当界面pause时,就不接收广播,从而减少不必要的系统开销。

一般来说,使用动态注册时,我们把BroadcastReceiver的类作为Activity的内部类,实现了在Activity中接收并处理广播。因为内部类与成员是同等级的,可以直接在onReceive中直接使用Activity的成员数据,去更新UI等操作。 使用静态注册时,我们是单独写一个BroadcastReceiver。在Manifest.xml进行注册时,添加IntentFilter的标签项来绑定Action,监听系统广播。例如这个监听系统开机的:

<receiver android:name=".BootCompleteReceiver" >
        <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
</receiver>
复制代码

一般动态注册设计给为页面提供广播,生命周期与Activity绑定,当页面不可见了,就不再接收广播。 而静态注册则为程序提供注册,程序没启动,也能接收广播。


发送广播 如何发送广播

完成上面两个步骤:定义我们的广播接收器、在Activity中注册广播接收器之后,我们就可以发送广播了。

由于是4大组件,所以发送广播和Activity、Service的启动类似:

Context.sendBroadcast(intent广播)
复制代码

要发送广播,肯定是先要有广播的对象啦。前面提过,广播实际上传递的是一个intent。 首先我们先实例化一个Intent,该Intent就是我们的广播所传递的消息载体。 我要为Intent添加我们要传递的信息以及Action(广播类型)。

创建完我们要广播的Intent,就可以发送广播了。发送广播我们有两种形式:

发送 标准广播  Context.sendBroadcast(intent);
发送 有序广播  Context.sendOrderedBroadcast(intent);
/
后面会讲到这两种广播,我们这里先以发送标准广播为例
复制代码

既然发送的是一个Intent,对于Intent大家应该都比较熟悉了,我们可以使用Intent的各个putExtras方法携带我们需要的数据。例如上图,我们给intent携带了一个Bundle。


如何接收广播?

好了,广播接收器的类也创建了并注册了,广播也创建并发送了,我该要去处理接收器接收到的广播了吧?

onReceive()

在我们创建的广播接收器类里面,覆盖了父类的onReceive()方法。在里面就可以使用参数当中发送来的intent。 注意,先判断intent是否为空,为了辨别广播的Action类型,我们需要判断intent的action: intent.getAction(),有点类似于我们点击函数switch中的view.getId() 因为action是一个字符串,是一个对象,不能用==。判断字符串是否相等,使用字符串工具类的equals方法TextUtils.equals(xxx,ooo);

问题?

在onReceive中可以执行耗时操作吗?receiver工作在主线程吗? 不能,因为和Activity、Service一样,工作在主线程,也就是UI线程当中,不能执行耗时操作,会导致ANR异常。 若不能执行耗时操作,如何解决? 和Service、Activity一样,开辟一个子线程作为工作线程。


###广播类型 == 有两种类型

发送 标准广播  Context.sendBroadcast(intent);
发送 有序广播  Context.sendOrderedBroadcast(intent);
复制代码
Normal broadcasts 标准广播 --- 一起进入办公室喝茶,所以无法被拦截

标准广播(Normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。标准广播的工作流程如图

Ordered broadcasts 有序广播 --- 有自己的顺序优先级 一个一个进入办公室喝茶

有序广播(Ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了

之前讲代码的都是以标准广播讲的,而发送有序广播只需要改动一行代码:

sendOrderedBroadcast(intent, null);

第二个参数是一个与权限相关的字符串,这里传入 null 就行了。
复制代码

这个时候的广播接收器是有先后顺序的,而且前面的广播接收器还可以将广播截断,以阻止其继续传播。 如何设定广播接收器的先后顺序呢? ==== 是在注册的时候进行设定的

android:priority 属性给广播接收器设置了优先级,最高为100。 在 onReceive()方法中调用了

 abortBroadcast();
复制代码

方法,就表示将这条广播截断,后面的广播接收器将无法再接收到这条广播

标准广播和有序广播有何区别?

类似于service、IntentService。 标准广播是异步的,在发送广播的同时,所有接收者基本同一时间接收到。 标准广播是有序的,优先级高的接收器先接收并处理广播消息。 处理完之后,决定是否要拦截abortBroadcast(),若不调用,则广播在onReceive后传递给下一个优先级的接收器。


补充,除了上面的全局性广播,还有一个效率奇高的本地广播 LocalBroadcast --- 应用中传递,速度快。若广播只发给应用自身,则使用LocalBroadcast。 可以作Service -- Activity 通信!!!?


BroadcastReceiver生命周期

命周期只有十秒左右,如果在 onReceive() 内做超过十秒内的事情,就会报ANR(Application No Response) 程序无响应的错误信息。 它的生命周期为从回调onReceive()方法开始到该方法返回结果后结束。


建议

适当用 :让广播真正拥有广播的尊严,当一个消息需要多个地方接收才用。若只是一个地方,则使用CallBack回调实现消息通信。 不滥用 : 广播太多,无法维护 ,因为可读性差,不知道代码间的联系。 能有LocalBroadcast则使用它。

转载于:https://juejin.im/post/5a5dee1051882573514f72aa

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值