LocalBroadcastManager源码阅读

思考

为什么需要两个map呢?

    private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceiver = new HashMap<>();
    private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
复制代码
  • 注册广播的时候,根据receiver对象和action值(注意是action值,不是IntentFilter)分别进行了归类,存在了上述两个集合中。
  • 发送广播的时候,先根据action值找出了所有对应的ReceiverRecord,然后再拿出ReceiverRecord存储的IntentFilter和Intent进行匹配,匹配上的取出其中的receiver,这个流程首先说明了mActions的存在意义,
  • 那mReceiver的存在意义又是啥呢?感觉很多余啊啊啊啊啊啊啊啊啊啊啊啊啊,这是我们只考虑了注册和发送广播,还有取消注册呢。
  • 没有mReceiver这个集合,根据mActions怎么取消呢,那就只能全量遍历mActions,遍历这个HashMap来一个个取出对应的集合,再遍历集合找出匹配的receiver并remove掉,这可是个全量的活啊,造孽啊。如果有mReceiver这个集合,则可以缩小检索范围,先mReceiver根据receiver这个key移除掉value,然后再根据这个receiver对应的ArrayList遍历出涉及到的action,再把mActions中action作为key对应的集合中涉及到此receiver的ReceiverRecord给remove掉,如果操作完之后,对应的集合为空了,则说明没有关于这个action的观察者了,可以从mActions中彻底移除了。
  • 同样的道理如果只用mReceiver而不用mActions,那么发送广播时就得全量遍历。
  • 可见,mReceiver是为了方便取消注册时检索,而mActions是为了方便发送广播时检索。这也是Map相对于List在检索上的优势体现。

扩展思考

为什么获取单列时使用的锁是mLock,而其他方法使用的锁是mReceivers???

答:其他方法基本都涉及到对mReceivers的读写改查,因此需要使用同一把锁,形成互斥,但是获取单列和这些方法并不存在数据的交集,因此不需要互斥,所以使用不同的锁。此处和锁定类的效果是一样的。
推荐阅读:Java中Synchronized的用法

获取单列

传入context,调用getApplicationContext,最终持有的是Application实例

    private static final Object mLock = new Object();
    private static LocalBroadcastManager mInstance;

    @NonNull
    public static LocalBroadcastManager getInstance(@NonNull Context context) {
        synchronized (mLock) {
            if (mInstance == null) {
                mInstance = new LocalBroadcastManager(context.getApplicationContext());
            }
            return mInstance;
        }
    }
复制代码

注册(锁mReceivers)

public void registerReceiver(@NonNull BroadcastReceiver receiver,
            @NonNull IntentFilter filter) {
         // 锁mReceivers
        synchronized (mReceivers) {
            ReceiverRecord entry = new ReceiverRecord(filter, receiver);
            // mReceivers键为receiver,值为ReceiverRecord,一对多
            ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
            if (filters == null) {
                filters = new ArrayList<>(1);
                mReceivers.put(receiver, filters);
            }
            filters.add(entry);
            for (int i=0; i<filter.countActions(); i++) {
                String action = filter.getAction(i);
            // mActions键为action,值为ReceiverRecord,一对多
                ArrayList<ReceiverRecord> entries = mActions.get(action);
                if (entries == null) {
                    entries = new ArrayList<ReceiverRecord>(1);
                    mActions.put(action, entries);
                }
                entries.add(entry);
            }
        }
    }
复制代码

取消注册(锁mReceivers)

    public void unregisterReceiver(@NonNull BroadcastReceiver receiver) {
       // 锁mReceivers
        synchronized (mReceivers) {
            // mReceivers是HashMap,移除掉receiver对应的ReceiverRecord集合
            final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
            if (filters == null) {
                return;
            }
            // 根据receiver对应的ReceiverRecord集合
            for (int i=filters.size()-1; i>=0; i--) {
                final ReceiverRecord filter = filters.get(i);
                filter.dead = true;
                // 遍历取出来每个IntentFilter中的action(多个)
                for (int j=0; j<filter.filter.countActions(); j++) {
                    final String action = filter.filter.getAction(j);
                    // 取出每个action对应的ReceiverRecord集合
                    final ArrayList<ReceiverRecord> receivers = mActions.get(action);
                    if (receivers != null) {
                        for (int k=receivers.size()-1; k>=0; k--) {
                            final ReceiverRecord rec = receivers.get(k);
                            // 如果ReceiverRecord中的receiver是取消注册的receiver,则从集合中移除
                            // 此处remove时,需要倒序遍历,源码很值得学习啊
                            if (rec.receiver == receiver) {
                                rec.dead = true;
                                receivers.remove(k);
                            }
                        }
                        // 如果receivers的长度为0了,说明没有关于这个action的观察者了,可以从mActions中彻底移除了
                        if (receivers.size() <= 0) {
                            mActions.remove(action);
                        }
                    }
                }
            }
        }
    }
复制代码

发送广播(锁mReceivers)

    // 精简代码
    public boolean sendBroadcast(@NonNull Intent intent) {
        // 锁mReceivers
        synchronized (mReceivers) {
            final String action = intent.getAction();
            final String type = intent.resolveTypeIfNeeded(
                    mAppContext.getContentResolver());
            final Uri data = intent.getData();
            final String scheme = intent.getScheme();
            final Set<String> categories = intent.getCategories();
            // action对应的ReceiverRecord,其实存储的是注册的receiver
            ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
            if (entries != null) {
                ArrayList<ReceiverRecord> receivers = null;
                for (int i=0; i<entries.size(); i++) {
                    ReceiverRecord receiver = entries.get(i);
                    if (receiver.broadcasting) {
                        // 相同的则不必再加入
                        // 为什么此处要增加这个判断呢???????????????
                        // 因为从注册的源码来看,如果我们重复调用了registerReceiver,
                        // 就会导致同一个receiver被重复加入mReceivers和mActions中,
                        // 这显然是需要避免的,因为这是粗心导致的,根本不存在同一个观察者需要被注册两次,尤其是IntentFilter还是一样的
                        continue;
                    }
                    // 根据IntentFilter判断是否有匹配的receiver
                    int match = receiver.filter.match(action, type, scheme, data,
                            categories, "LocalBroadcastManager");
                    if (match >= 0) {
                        if (receivers == null) {
                            // 有匹配的再初始化集合,源码严格遵循使用时再初始化,避免没有匹配时也初始化集合,浪费内存空间
                            receivers = new ArrayList<ReceiverRecord>();
                        }
                        // 有匹配的receiver,则加入集合中
                        receivers.add(receiver);
                        // 标记为已经加入,防止重复添加
                        receiver.broadcasting = true;
                    } else {
                        // 没有匹配的receiver,源码打印了一堆Log
                    }
                }

                if (receivers != null) {
                    for (int i=0; i<receivers.size(); i++) {
                        // 取消添加标记,重置状态,以便下次发送广播
                        receivers.get(i).broadcasting = false;
                    }
                    mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
                    if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
                        mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
                    }
                    return true;
                }
            }
        }
        return false;
    }
复制代码

处理广播(锁mReceivers)

// 注意看,这个Handler时主线程的哦
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);
                }
            }
};
// 处理广播
void executePendingBroadcasts() {
        while (true) {
            final BroadcastRecord[] brs;
             // 锁mReceivers
            synchronized (mReceivers) {
                final int N = mPendingBroadcasts.size();
                if (N <= 0) {
                    return;
                }
                brs = new BroadcastRecord[N];
                mPendingBroadcasts.toArray(brs);
                mPendingBroadcasts.clear();
            }
            for (int i=0; i<brs.length; i++) {
                final BroadcastRecord br = brs[i];
                final int nbr = br.receivers.size();
                for (int j=0; j<nbr; j++) {
                    final ReceiverRecord rec = br.receivers.get(j);
                    if (!rec.dead) {
                        // 调用我们的receiver的onReceive方法
                        // 看清楚了,这里时mAppContext啊,这个值可是context.getApplicationContext()
                        rec.receiver.onReceive(mAppContext, br.intent);
                    }
                }
            }
        }
    }
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享