LocalBroadcastManager原理分析及应用

本文详细介绍了Android中LocalBroadcastManager的工作原理,包括它的优点、注册与反注册过程、异步与同步发送广播的方式,以及如何在实际应用中使用本地广播进行通信。通过源码分析,揭示了LocalBroadcastManager如何在应用内部高效、安全地实现广播机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

Android页面或模块之间通信的方法有很多,如Intent传值、startActivityForResult、EventBus(RxBus)等,大家追求的无非是解耦以及高灵活性;我们自己的应用中使用了基于Android消息机制封装的一套通信体系,且不谈这些,今天的主角是本地广播。

本地广播是系统提供的一种应用内通信方式,它跟全局广播相比,其运行机制是不同的。全局广播是系统级别的,需要跨进程调用,而且作用域是整个设备,而本地广播的作用域只在当前应用之内,因此无需IPC的过程,本应用发送的本地广播,其他应用接收不到,其他应用发送的本地广播,本应用也接收不到。

本地广播的优点

  1. 本地广播作用于App内部,广播数据不会泄露,本应用也不会接收到其他应用的广播,因此安全性较高
  2. 本地广播是在应用内部执行,无需跨进程逻辑,与普通广播相比效率更高
  3. 使用简单,无需静态注册

原理分析

本地广播的原理也很简单,大概流程如下

  1. 首先需要接收广播的页面创建一个BroadcastReceiver(广播声明跟全局广播是一样的)并注册到一个应用内的本地广播接收器列表(注册方式跟全局广播不同,下文会详细说明)
  2. 某个页面利用Intent发送广播(发送方式跟全局广播不同,下文会详细说明)
  3. 本地广播接收器列表根据IntentFilter匹配得到可以接收该广播的BroadcastReceiver,然后匹配的广播接收器会响应广播(注意这里区分广播的异步与同步发送)
  4. 在适当时候反注册BroadcastReceiver,比如Activity的onDestroy()回调中

为了方便大家的使用,Android提供了LocalBroadcastManager类(姑且称之为本地广播管理器),该类帮我们封装了注册、反注册、广播发送等过程,接下来分析一下源码实现。

LocalBroadcastManager定义

首先LocalBroadcastManager定义为一个单例,方便App内全局使用。

private static LocalBroadcastManager mInstance;

public static LocalBroadcastManager getInstance(Context context) {
    synchronized (mLock) {
        if (mInstance == null) {
            mInstance = new LocalBroadcastManager(context.getApplicationContext());
        }
        return mInstance;
    }
}

private LocalBroadcastManager(Context context) {
    mAppContext = context;
    mHandler = new Handler(context.getMainLooper()) {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_EXEC_PENDING_BROADCASTS:
                    executePendingBroadcasts();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };
}

注意到LocalBroadcastManager的构造函数中创建了一个Handler实例,并且是运行在主线程的,它响应一种what为MSG_EXEC_PENDING_BROADCASTS的消息,这是用来处理异步广播的,具体如何处理稍后说明。

两个内部类

对于广播接收器的注册过程,并非简单地把BroadcastReceiver进行注册,而是进行了简单的包装,这里涉及到LocalBroadcastManager的两个内部类,如下:

ReceiverRecord
private static class ReceiverRecord {
   
    final IntentFilter filter;
    final BroadcastReceiver receiver;
    boolean broadcasting;

    ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
        filter = _filter;
        receiver = _receiver;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder(128);
        builder.append("Receiver{");
        builder.append(receiver);
        builder.append(" filter=");
        builder.append(filter);
        builder.append("}");
        return builder.toString();
    }
}

顾名思义,ReceiverRecord简单封装了BroadcastReceiver和IntentFilter。

BroadcastRecord
private static class BroadcastRecord {
   
    final Intent intent;
    final ArrayList<ReceiverRecord> receivers;

    BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers) {
        intent = _intent;
        receivers = _receivers;
    }
}

BroadcastRecord也很简单,封装了广播Intent以及能够匹配该Intent的接收器列表(这里并非直接是BroadcastReceiver,而是包装类ReceiverRecord)。

基于上述两个包装类,LocalBroadcastManager提供了如下两个HashMap用来存储注册的接收器

private final HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers
        = new HashMap<BroadcastReceiver, ArrayList<IntentFilter>>();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions
        = new HashMap<String, ArrayList<ReceiverRecord>>();

此外还有一个叫mPendingBroadcasts的容器如下

private final ArrayList<BroadcastRecord> mPendingBroadcasts
        = new ArrayList<BroadcastRecord>();

它是用来存储待处理广播的列表,其元素为BroadcastRecord。

注册过程

注册过程源码如下,具体流程分析请看注释

/**
 * Register a receive for any local broadcasts that match the given IntentFilter.
 *
 * @param receiver The BroadcastReceiver to handle the broadcast.
 * @param filter Selects the Intent broadcasts to be received.
 *
 * @see #unregisterReceiver
 */
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    // 加锁同步
    synchronized (mReceivers) {
        // 将BroadcastReceiver和IntentFilter封装成ReceiverRecord
        ReceiverRecord entry = new ReceiverRecord(filter, receiver);
        // BroadcastReceiver作为HashMap的key,注意一般来说注册时一个BroadcastReceiver对应一个IntentFilter。但有一种情况下同一个页面内使用同一个BroadcastReceiver,配合不同的IntentFilter注册多次;更极端情况是应用内只有一个BroadcastReceiver,使用不同的Intent
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值