广播组件

广播组件

Posted by candy1126xx on March 29, 2017

基于发布 / 订阅事件模型。发布 / 订阅事件模型由消息订阅者、消息发布者、消息中心构成。

广播分为本地广播和全局广播。

本地广播

进程内通信,不可跨进程。

  • 消息订阅者:BroadcastReceiver。
  • 消息发布者:任何地方都可以发布广播。
  • 消息中心:LocalBroadcastManager。

注意控制BroadcastReceiver的生命周期,应与所对应的Activity、Service、Fragment等组件的生命周期一致。

// 1个含有n个IntentFilter的广播接收者被拆分成n个ReceiverRecord
class ReceiverRecord {
        final IntentFilter filter;
        final BroadcastReceiver receiver;
        boolean broadcasting;
}

// 描述一条已经经过匹配但没有执行的广播
class BroadcastRecord {
    final Intent intent;                            // 广播携带的Intent
    final ArrayList<ReceiverRecord> receivers;      // 可以处理这条广播的接受者
}

class LocalBroadcastManager {

	// Application对象。也说明本地广播是应用进程单例的。
	private final Context mAppContext;
	
	// 记录BroadcastReceiver和IntentFilter的对应关系。
	// 1个BroadcastReceiver对应多个IntentFilter。
	private final HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers = new HashMap<>();
	
	// 记录Action和ReceiverRecord的对应关系。
	// 1个Action可能匹配多个IntentFilter。
    private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();

    // 记录所有通过匹配但没有执行的广播。
    private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();
    
    // 单例
    private static LocalBroadcastManager mInstance;
    
    // 发送和处理MSG_EXEC_PENDING_BROADCASTS。
    // 工作在主线程。并且LocalBroadcastManager的暴露方法都是加了内置锁的,所以是线程安全的。
    private final Handler mHandler;
}

注册广播接收者

LocalBroadcastManager.registerReceiver()。参数是BroadcastReceiver receiver, IntentFilter filter。

  1. 申请mReceivers的内置锁;
  2. 以receiver、filter构建ReceiverRecord;
  3. 把receiver 、filter加入mReceivers;
  4. 遍历filter中的Action,把ReceiverRecord加入mActions;
  5. 释放mReceivers的内置锁。

注销广播接收者

LocalBroadcastManager.unregisterReceiver()。参数是BroadcastReceiver receiver。

  1. 申请mReceivers的内置锁;
  2. 从mReceivers中删除以receiver为键的键值对;
  3. 根据被删除的键值对的值(ArrayList),删除mActions中对应的ReceiverRecord;
  4. 如果删除后ArrayList的元素数量为0,则删除这个键值对;
  5. 释放mReceivers的内置锁。

发送广播

LocalBroadcastManager.sendBroadcast()。参数是Intent。

  1. 申请mReceivers的内置锁;
  2. 获取Intent的Action,并找到mActions中对应的ArrayList
  3. 用ReceiverRecord. filter匹配Intent的其它属性,把通过匹配的加入集合,记为receivers;
  4. 以Intent、receivers构建BroadcastRecord并加入mPendingBroadcasts;
  5. mHandler发送信息MSG_EXEC_PENDING_BROADCASTS。
  6. 释放mReceivers的内置锁。
  7. 处理MSG_EXEC_PENDING_BROADCASTS,while死循环直到mPendingBroadcasts中没有元素;
  8. 遍历mPendingBroadcasts,遍历receivers,调用BroadcastReceiver.onReceive(),传入的参数Context是Application对象;

发送同步广播

LocalBroadcastManager.sendBroadcastSync()。与发送广播相似,区别在于匹配之后立即调用处理方法(8),效果就是立即执行onReceive()且阻塞。

全局广播

可以跨进程。

  • 消息订阅者:BroadcastReceiver。
  • 消息发布者:Context子类。
  • 消息中心:AMS。
// 描述一条广播
class BroadcastRecord extends Binder

// 系统中共有2个广播队列,1个用于前台优先级,1个用于后台优先级
class BroadcastQueue

class ReceiverList extends ArrayList<BroadcastFilter>

class ActivityManagerService {
	
	// 键是IIntentReceiver.Stub对象,值是BroadcastFilter集合;
	final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
	
	// 负责匹配全局广播的IntentResolver
	final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver;
}

接收AMS的跨进程消息

业务层

  • 定义接口:IIntentReceiver
  • 服务端:IIntentReceiver.Stub
  • 客户端:IIntentReceiver.Proxy

实现层LoadedApk.ReceiverDispatcher.InnerReceiver

注册广播接收者

ContextImpl.registerReceiverInternal() -> AMS.registerReceiver()。参数ApplicationThrad对象,包名,IIntentReceiver.Stub对象, IntentFilter。

注意:全局广播的BroadcastReceiver与IntentFilter是一一对应的。

  1. 根据ApplicationThrad对象找到ProcessRecord对象;
  2. 创建ReceiverList对象并加入mRegisteredReceivers;
  3. 创建BroadcastFilter对象并加入mReceiverResolver;

注销广播接收者

ContextImpl.unregisterReceiver() -> AMS.unregisterReceiver()。参数IIntentReceiver.Stub对象。

  1. 由IIntentReceiver.Stub对象获取ReceiverList对象;
  2. 处理ReceiverList.curBroadcast不为空,即有广播正在处理的情况;
  3. 删除mRegisteredReceivers中以IIntentReceiver.Stub对象为键的键值对;
  4. 删除mReceiverResolver中有关ReceiverList对象的数据。

发送广播

ContextImpl.sendBroadcast() -> AMS.broadcastIntent()。参数ApplicationThrad对象、Intent。

  1. 根据ApplicationThrad对象找到ProcessRecord对象;
  2. 检查:非系统进程不许发系统广播;
  3. 处理系统广播;
  4. 处理粘性广播;
  5. 匹配Intent,收集可处理广播的组件;
  6. 构造BroadcastRecord并加入BroadcastQueue;
  7. 通知BroadcastQueue开始运转。

有序广播

有序广播的有序,是指高优先级的BroadcastReceiver会优先截获这个消息,并且可以将这个消息删除。

普通广播和粘性广播不能被截获,而有序广播是可以被截获的。

粘性广播

粘性广播在发送后就一直存在于系统的消息容器里面,等待对应的处理器去处理,如果暂时没有处理器处理这个消息则一直在消息容器里面处于等待状态,粘性广播的Receiver如果被销毁,那么下次重建时会自动接收到消息数据。

粘性广播一般用来确保重要的状态改变后的信息被持久保存,并且能随时广播给新的广播接收器,比如电源的改变,因为耗电需要一个过程,前一个过程必须提前得到,否则可能遇到下次刚好接收到的广播后系统自动关机了,随之而来的是kill行为,所以对某些未处理完的任务来说,后果很严重。