Android Broadcast原理分析之LocalBroadcast(三)

目录

  • LocalBroadcastManager简介
  • LocalBroadcastManager使用
  • 源码解析
  • 总结

1. LocalBroadcastManager简介

前面的文章介绍了常用的Broadcast原理,这种广播是经过系统调度的,不论是动态注册还是静态注册,不论是有序广播还是无序广播,都要经过ams,好处很显然,可以实现跨进程之间的通信,而且有很多广播本身就是由系统发出的,我们需要在APP的进程中监听,但是也是有坏处的,因为AMS其实是很繁忙的,如果出现比较特殊的情况导致AMS被阻塞,就可能会影响我们自身收到receiver的时间,甚至收不到,这样就可能会影响到APP自身的业务。
Android中也是考虑到了这种情况,因此在v4包中引入了LocalBroadcastManager,顾名思义,叫做本地广播,也就是只在APP的自身进程中运行,不会被其他情况干扰,当然这个不能用作跨进程通信的手段。

2. LocalBroadcastManager使用

核心类就是LocalBroadcastManager,这个类的方法并不多,但是也涵盖了常用的registerReceiver,unregisterReceiver,sendBroadcast等方法。
先来看看其中主要都有那些方法:

单例模式获取LocalBroadcastManager
public static LocalBroadcastManager getInstance(Context context);

广播注册
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter);

取消注册
public void unregisterReceiver(BroadcastReceiver receiver);

发送广播
public boolean sendBroadcast(Intent intent);

同步发送广播
public void sendBroadcastSync(Intent intent);

执行广播派发
private void executePendingBroadcasts();

可以看到,和平时使用的广播没有太大区别,不过需要通过getInstance获取一个单例之后操作,其中有一个方法看起来没有见过,executePendingBroadcasts,而且是一个private方法,接下来从源码看一下这个LocalBroadcast的实现。

3. 源码解析

3.1 getInstance

    private static LocalBroadcastManager mInstance;

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

通过ApplicationContext创建单例。

3.2 registerReceiver

    public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        // mReceivers是一个hashmap
        // key是BroadcastReceiver,value是receiverRecord的list
        synchronized (mReceivers) {
            //  根据filter和receiver创建ReceiverRecord
            ReceiverRecord entry = new ReceiverRecord(filter, receiver);
            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同样是一个hashmap
                // key是广播action,value是ReceiverRecord的list
                ArrayList<ReceiverRecord> entries = mActions.get(action);
                if (entries == null) {
                    entries = new ArrayList<ReceiverRecord>(1);
                    mActions.put(action, entries);
                }
                entries.add(entry);
            }
        }
    }

ReceiverRecord中就只存了broadcastReceiver以及intentFilter
这段逻辑并不复杂,主要实现以下三步:

  1. 根据receiver和filter创建ReceiverRecord
  2. 将上面创建的record放入到mReceivers的value的list中
  3. 对本次广播的filter中所有action,在mAction的value中分别放入ReceiverRecord对象
    经过注册最终的结果是这样:
    mReceivers中存放的是已注册的receiver以及其对应的ReceiverRecord,同一个receiver如果多次用相同的filter不会生效多次,但是如果filter不同注册多次,那么就会在mReceivers存储多个ReceiverRecord;
    mAction中存放的是已注册的所有action,以及这个action对应的ReceiverRecord,如果这个filter中有多个action,那么就会存储多个相同的ReceiverRecord。

3.3 unregisterReceiver

    public void unregisterReceiver(BroadcastReceiver receiver) {
        synchronized (mReceivers) {
            final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
            if (filters == null) {
                return;
            }
            for (int i=filters.size()-1; i>=0; i--) {
                final ReceiverRecord filter = filters.get(i);
                filter.dead = true;
                for (int j=0; j<filter.filter.countActions(); j++) {
                    final String action = filter.filter.getAction(j);
                    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);
                            if (rec.receiver == receiver) {
                                rec.dead = true;
                                receivers.remove(k);
                            }
                        }
                        if (receivers.size() <= 0) {
                            mActions.remove(action);
                        }
                    }
                }
            }
        }
    }
  1. 取消注册的时候,因为mReceivers的key是receiver,直接把value移除即可。
  2. 从移除的value(ReceiverRecord)的list中遍历,分别拿出其中的filter中的action,前面两步主要是为了拿到本次取消注册的所有action,拿到action后,遍历所有的action,根据action去mActions拿到这个action对应的所有的ReceiverRecord对象列表,把这个列表中的receiver和要移除的receiver相等的ReceiverRecord移除。

3.4 sendBroadcast

    public boolean sendBroadcast(Intent intent) {
        synchronized (mReceivers) {
            final String action = intent.getAction();
            // 根据指定的schema获取intent的type
            final String type = intent.resolveTypeIfNeeded(
                    mAppContext.getContentResolver());
            // 获取uri
            final Uri data = intent.getData();
            final String scheme = intent.getScheme();
            final Set<String> categories = intent.getCategories();
            // 根据action,拿到所有注册了监听这个action的ReceiverRecord
            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);
                    // 因为不同的action中,可能有相同的ReceiverRecord,需要判断状态
                    // 如果正在发送了就下一个
                    if (receiver.broadcasting) {
                        continue;
                    }
                    // 根据ReceiverRecord中的record匹配
                    // 匹配成功之后,就加入到要派发的列表中
                    int match = receiver.filter.match(action, type, scheme, data,
                            categories, "LocalBroadcastManager");
                    if (match >= 0) {
                        if (receivers == null) {
                            receivers = new ArrayList<ReceiverRecord>();
                        }
                        receivers.add(receiver);
                        receiver.broadcasting = true;
                    }
                }
                // 到这里就找到了所有的监听这个action的receiver

                if (receivers != null) {
                    for (int i=0; i<receivers.size(); i++) {
                        receivers.get(i).broadcasting = false;
                    }
                    // 把要派发的广播加入到mPendingBroadcasts中
                    mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
                    // 发送message
                    if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
                        mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
                    }
                    return true;
                }
            }
        }
        return false;
    }

收集需要派发的receiver,并post消息到主线程

3.5 handleMessage

    private LocalBroadcastManager(Context context) {
        mAppContext = context;
        // 可以看到这里用的是主线程的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);
                }
            }
        };
    }

这里走到了前面我们提到的那个private方法,看来这个方法是派发的核心了。

3.6 executePendingBroadcasts

    private void executePendingBroadcasts() {
        // 死循环,直到广播都派发完毕才return
        while (true) {
            final BroadcastRecord[] brs;
            synchronized (mReceivers) {
                final int N = mPendingBroadcasts.size();
                // 没有需要派发的广播那就return了
                if (N <= 0) {
                    return;
                }
                brs = new BroadcastRecord[N];
                mPendingBroadcasts.toArray(brs);
                mPendingBroadcasts.clear();
            }
            // 便利了所有的receiver之后,回调了receiver的onReceive
            // mAppContext正是创建单例时的context
            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) {
                        rec.receiver.onReceive(mAppContext, br.intent);
                    }
                }
            }
        }
    }

果然,真正的广播派发以及receiver的回调就在这里。
前面有提到还有一个方法sendBroadcastSync

3.7 sendBroadcastSync

    public void sendBroadcastSync(Intent intent) {
        if (sendBroadcast(intent)) {
            executePendingBroadcasts();
        }
    }

从名字上看意思应该是同步发送广播,事实上正是这样,在调用了sendBroadcast之后,其中是经过了向主线程post消息,然后主线程去处理receiver的,而这里sendBroadcast返回值为true就代表收集到了receiver,直接在当前线程开始调度了。因为在executePendingBroadcasts方法中是持锁派发,而且有对需要派发广播的数量校验,因此并不需要担心广播会被派发多次。

总结

  1. 依旧是经典的观察者模式
  2. 注册的时候通过mReceivers/mActions两个map从不同的维度保存了已注册的receiver
  3. 发送广播之后根据action以及filter的匹配,查找需要派发的receiver
  4. 正常流程是post消息到主线程派发
  5. 可以选择在当前线程同步进行广播派发
    原文作者:glearn.
    原文地址: https://blog.csdn.net/u011733869/article/details/83869528
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞