Android LocalBroadcastReceiver本地广播

由于之前的广播都是 全局的 ,所有应用程序都可以接收到,这样就很容易会引起安全性的问题,比如说我们发送一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。
  为了能够简单地解决广播的安全性问题,Android引入了一套 本地广播机制 ,使用这个机制发出的广播 只能够在应用程序的内部进行传递 ,并且 广播接收器 也只能接收来自应用程序发出的广播,这样所有的安全性问题就都不存在了。


核心用法
  使用LocalBroadcastManager来管理广播:
  1. 调用LocalBroadcastManager.getInstance(this)来获得实例
  2. 调用xx.registerReceiver(BroadcastReceiver receiver,IntentFilter filter)来注册广播;(receiver本地广播接收器)
  3. 调用xx.sendBroadcast()发送广播
  4. 调用xx.unregisterReceiver()取消注册
注意事项
  1. 本地广播无法通过静态注册来接收,相比起系统全局广播更加高效
  2. 在广播中启动activity的话,需要为intent加入FLAG_ACTIVITY_NEW_TASK的标记,不然会报错,因为需要一个栈来存放新打开的activity。
  3. 广播中弹出AlertDialog的话,需要设置对话框的类型为:TYPE_SYSTEM_ALERT不然是无法弹出的。

1:本地广播实现Activity传递数据:
Android LocalBroadcastReceiver本地广播_第1张图片

Android LocalBroadcastReceiver本地广播_第2张图片
源码分析:
1:getInstance(this);用了标准的单利模式;
2:构造中初始化了一个Handle对象,用于对广播的分发;
3:广播的注册、反注册、发送流程
如果让我们来自己来实现广播的注册、反注册、发送我们会怎么搞呢?
首先,注册的时候需要提供BroadcastReceiver和对应的IntentFilter,我们可以对这种数据结构进行封装,放到一个类中ReceiverRecord。
然后维护一个ReceiverRecord对象列表,用于记录当前注册了哪些BroadcastReceiver。可以简单使用ArrayList.
在unRegister的时候根据提供的BroadcastReceiver对象,遍历List找出对应的receiver进行移除。
这样每来一个unRegister我们都需要对Receiver列表做一次遍历,开销有点大,在查操作比较多的时候我们可以使用MAP。
HashMap
ReceiverRecord中已经包含BroadcastReceiver对象了,所以value直接使用IntentFilte就行了,简化数据结构。
那如果一个Receiver注册了多个IntentFilter呢?比如说一个receiver对象注册两次传入不同的IntentFilter.所以Value需要改造为ArrayList。 最终用于维护当前Reciver对象列表的数据结构是这样事儿的:
HashMap> mReceivers.
当删除时可以通过receiver对象为key在map中快速查找并移除。
发送广播的时候呢?我们知道sendBroadcast时只传入了Intent对象,Intent携带了Action用于和已经注册的receiver匹配。在查找receiver时,需要对 HashMap> mReceivers 的Value进行遍历,每一个Value ArrayList 又需要遍历一次。这个查找的开销实在太大了。
看来我们为了实现Action和receiver的快速匹配需要再维护一个数据结构了。同样是频繁查找的需求使用HashMap.
将Action作为Key,value肯定是与之匹配的receiver了。因为一个Action可能会对应多个receiver,receiver注册的时候可以使用相同的Action.所以value需要使用ArrayList. 当发送广播时可以快速根据Action找到对应的receiver。对了,不仅仅要使用Action匹配,filter中还有其他信息匹配成功之后才能确认是真正的receiver.所以需要使用ReceiverRecord作为value,因为不仅包含了receiver对象,同时包含了IntentFilter.所以最终的数据结构是 HashMap>.
我们来看Google是怎么实现的呢?
先来看两个内部类:
//内部类ReceiverRecord Receiver记录:用于记录reciver,对应的IntentFilter和是否在broadcast状态
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();
        }
    }

    //BroadcastRecord 广播记录:用于记录广播的intent以及有哪些对应的ReceiverRecord
    private static class BroadcastRecord {
        final Intent intent;
        final ArrayList receivers;

        BroadcastRecord(Intent _intent, ArrayList _receivers) {
            intent = _intent;
            receivers = _receivers;
        }
    }
再来看几个成员变量:
//维护一个mReceivers Map 记录一个所有的receiver,每一个对应哪些Intentfilters。主要用于记录当前有哪些receiver需要维护接受广播。 //方便广播的反注册,反注册时可以快速找到filter从而找到Action,从而操作mAction.试想如果没有mReceivers,只能全部遍历mAction找出所有BroadcastRecord,从而找到filter和Action,性能很差。 private final HashMap> mReceivers = new HashMap>(); //维护一个mActions Map 记录所有的Action,每一个对应哪些ReceiverRecord private final HashMap> mActions = new HashMap>(); //维护一个List,记录当前正处在等待状态的广播BroadcastRecord,通过BroadcastRecord可以找到intent对应的receivers private final ArrayList mPendingBroadcasts = new ArrayList();
广播的发送过程
/**
     * 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) {
            ReceiverRecord entry = new ReceiverRecord(filter, receiver);
            //查找receiver有没有在mReceiver记录中,如果不在需要添加进去。
            ArrayList filters = mReceivers.get(receiver);
            if (filters == null) {
                filters = new ArrayList(1);
                mReceivers.put(receiver, filters);
            }
            //将IntentFilter加入receiver对应的匹配规则中。filters为mReceivers map的value,类型是IntentFilter的ArrayList。
            //同一个receiver可能有多个IntentFilter。mReceivers就记录了所有的receiver,并且指明每一个receiver所能匹配到的IntentFilter.
            filters.add(filter);
            //开始遍历IntentFilter中的Action.检查Action是否在mActions,如果不在不要添加进去。
            //mActions是Action为Key , ArrayList为value的MAP。
            //记录了当前有那些Action,并且每个Action对应的Receiver(ReceiverRecord)是哪个。
            for (int i=0; i entries = mActions.get(action);
                if (entries == null) {
                    entries = new ArrayList(1);
                    mActions.put(action, entries);
                }
                //将ReceiverRcoder对象加入entries:entries是该Action对应的ReceiverRecord列表。
                entries.add(entry);
            }
        }
    }


广播的反注册过程


    /**
     * Unregister a previously registered BroadcastReceiver.  All
     * filters that have been registered for this BroadcastReceiver will be
     * removed.
     *
     * @param receiver The BroadcastReceiver to unregister.
     *
     * @see #registerReceiver
     */
    public void unregisterReceiver(BroadcastReceiver receiver) {
        synchronized (mReceivers) {
            //在Receiver列表中移除要注销的receiver,返回对应的filters.
            ArrayList filters = mReceivers.remove(receiver);
            if (filters == null) {
                return;
            }
            //在Action Map中移除对应的receiver
            for (int i=0; i receivers = mActions.get(action);
                    if (receivers != null) {
                        for (int k=0; k categories = intent.getCategories();

            final boolean debug = DEBUG ||
                    ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
            if (debug) Log.v(
                    TAG, "Resolving type " + type + " scheme " + scheme
                    + " of intent " + intent);

            //根据Action从mActions MAP 中取对应的receivers.
            ArrayList entries = mActions.get(intent.getAction());
            if (entries != null) {
                if (debug) Log.v(TAG, "Action list: " + entries);

                ArrayList receivers = null;
                //遍历receivers找出符合IntentFilter条件的
                for (int i=0; i= 0) {
                        if (debug) Log.v(TAG, "  Filter matched!  match=0x" +
                                Integer.toHexString(match));
                        if (receivers == null) {
                            receivers = new ArrayList();
                        }
                        receivers.add(receiver);
                        //将receiver 是否在分发中置位true
                        receiver.broadcasting = true;
                    } else {
                        if (debug) {
                            String reason;
                            switch (match) {
                                case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
                                case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
                                case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
                                case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
                                default: reason = "unknown reason"; break;
                            }
                            Log.v(TAG, "  Filter did not match: " + reason);
                        }
                    }
                }
                //将broadcasting置位false 加入mPendingBroadcasts等待队列中.
                if (receivers != null) {
                    for (int i=0; i

总结
1.LocalBroadcast是APP内部维护的一套广播机制,有很高的安全性和高效性。
所以如果有APP内部发送、接收广播的需要应该使用LocalBroadcast。
2.Receiver只允许动态注册,不允许在Manifest中注册。
3.LocalBroadcastManager所发送的广播action,只能与注册到LocalBroadcastManager中BroadcastReceiver产生互动。



你可能感兴趣的:(Android)