四大组件之Broadcast详解

广播相关定义

  1. 广播是一个全局的监听器,是Android的四大组件之一,分为两个角色:广播发送者和广播接收者。
  2. 作用:监听/接收应用发出的广播消息并作出响应。
  3. 应用场景:不同组件之间的通信(包括应用内和应用间);多线程下的通信;与android系统的通信。
  4. 广播采用的是观察者的设计模式,基于消息的发布 / 订阅事件模型,将广播的发送者和接收者解耦,使得系统方便集成,更易扩展。
  • 模型中的三个角色

1、消息订阅者(广播接收者)
2、消息发布者(广播发布者)
3、消息中心(AMS,即Activity Manager Service)

  • 示意图 & 原理如下
image

注册时,描述注册的广播接收者的BroadcastFilter添加到IntentResolver类型的mReceiverResolver中,这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了。

image.png

AMS最终receiver注册到HashMap,receiver被封装成dispatcher注册到BroadcastQueue,到这里BroadcastReceiver的注册基本完毕。

image.png
image.png

ContextImpl.sendBroadcast() 发送广播时,同样用到的是binder IPC机制与AMS进行通信。接着来看下AMS中的broadcastIntent()方法,最终会调用broadcastIntentLocked()方法,这个方法比较长,对粘性广播、系统广播、有序广播和正常广播分别进行了处理,最终会匹配相应的注册了的广播接收器。最后执行BroadcastQueue的scheduleBroadcastsLocked()方法,也就是发送广播给接收器。 最终也执行到performReceiveLocked 这里的app.thread其实就是ActivityThread,我们再看ActivityThread. scheduleRegisteredReceiver方法 这里的receiver就是之前在注册广播时获取的LoadApk.ReceiverDispatcher.InnerReceiver(Binder接口 IPC过程)然后再通过LoadApk.ReceiverDispatcher.performReceive()方法通过handle post出一个Runnable:这里通过ActivityThread.H的handler对象post了一个线程,最终是通过ActivityThread.H对象post出一个线程,将 receiver.onReceive(mContext, intent); 方法的调用回到了主线程。

广播静态注册和动态注册

在使用广播的时候,我们需要自定义广播接受者BroadcastReceiver来处理我们的广播业务逻辑。
1、继承BroadcastReceiver基类
2、必须复写抽象方法onReceive()方法(接收 到广播后系统会回调)

注意:默认情况下,**广播接收器运行在 UI 线程,因此,onReceive()方法不能执行耗时操作,否则将导致ANR。而且不支持在接收方法里开启多线程。
**
广播接收器要先在系统中注册,注册的方式分为两种:静态注册和动态注册。

  • 静态注册
    注册方式:在AndroidManifest.xml里通过<receive>标签声明。
<receiver 
    android:enabled=["true" | "false"]
//此broadcastReceiver能否接收其他App的发出的广播
//默认值是由receiver中有无intent-filter决定的:如果有intent-filter,默认值为true,否则为false
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
//继承BroadcastReceiver子类的类名
    android:name=".mBroadcastReceiver"
//具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收;
    android:permission="string"
//BroadcastReceiver运行所处的进程
//默认为app的进程,可以指定独立的进程
//注:Android四大基本组件都可以通过此属性指定自己的独立进程
    android:process="string" >

//用于指定此广播接收器将接收的广播类型
//本示例中给出的是用于接收网络状态改变时发出的广播
 <intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>
  • 动态注册
    注册方式:在代码中调用Context.registerReceiver()方法
// 1. 实例化BroadcastReceiver子类 &  IntentFilter
     mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
     IntentFilter intentFilter = new IntentFilter();

    // 2. 设置接收广播的类型
    intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

    // 3. 动态注册:调用Context的registerReceiver()方法
     registerReceiver(mBroadcastReceiver, intentFilter);

动态注册的registerReceiver和unregisterReceiver一定要成对出现,不然会有内存溢出风险,并且不能重复调用。所以最好注册或注销的时候设个标记判断一下注册状态。
如果要在退到后台或者不在当前页面也能收到广播,那么在onCreate()方法注册,在onDestory()方法注销,注册时判断一下设置的标记。

  • 两者区别

     
    image

广播类型

  1. 按类型分:
  • 全局广播:发出的广播可以被其他任意的应用程序接收,或者可以接收来自其他任意应用程序的广播。

  • 本地广播:只能在应用程序的内部进行传递的广播,广播接收器也只能接收内部的广播,不能接受其他应用程序的广播。

具体使用1:将全局广播设置成局部广播

1、注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;
2、在广播发送和接收时,增设相应权限permission,用于权限验证;
3、发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

具体使用2 - 使用封装好的LocalBroadcastManager类:
使用方式上与全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将参数的context变成了LocalBroadcastManager的单一实例。
对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册。(因为静态注册主要是为了让程序在未启动的情况下也能收到广播,而发动本地广播的时候,我们的程序已经是启动了,所以,自然是没有静态注册这个方法)

//注册应用内广播接收器
//步骤1:实例化BroadcastReceiver子类 & IntentFilter mBroadcastReceiver 
mBroadcastReceiver = new mBroadcastReceiver(); 
IntentFilter intentFilter = new IntentFilter(); 

//步骤2:实例化LocalBroadcastManager的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);

//步骤3:设置接收广播的类型 
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

//步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册 
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);

//取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);

//发送应用内广播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);********
  1. 按机制分:
  • 标准广播(无序广播):所有的接收者都会接收事件,不可以被拦截,不可以被修改。

  • 有序广播:按照优先级,一级一级的向下传递,接收者可以修改广播数据,也可以终止广播事件。

广播接受者接收广播的顺序规则:
按照Priority属性值从大-小排序;
Priority属性相同者,动态注册的广播优先

特点:
接收广播按顺序接收先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;
先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播。

有序广播和普通广播的用法差别只在发送广播的方法,有序广播用 sendOrderedBroadcast(intent);

参考链接:
https://www.jianshu.com/p/ca3d87a4cdf3

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vinson武

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值