欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android应用内广播LocalBroadcastManager机制

程序员文章站 2022-04-28 13:23:28
1. 简介 通常我们在使用android广播的时候都会直接将广播注册到的ams当中,由于ams任务繁忙,一般可能不会立即能处理到我们发出的广播,如果我们使用广播是在应用内的单个进程中使用,则完全可以...

1. 简介

通常我们在使用android广播的时候都会直接将广播注册到的ams当中,由于ams任务繁忙,一般可能不会立即能处理到我们发出的广播,如果我们使用广播是在应用内的单个进程中使用,则完全可以采用localbroadcastmanager来处理。localbroadcastmanager采用的是handler的消息机制来处理的广播,而注册到系统中的是通过binder机制实现的,速度是应用内广播要快很多。不过由于handler的消息机制是为了同一个进程的多线程间进行通信的,因而跨进程时无法使用应用内广播。

1.1 使用

在使用上和普通的broadcast类似,主要分5步。具体如下:

//1. 自定义广播接收者
public class localreceiver extends broadcastreceiver {
    public void onreceive(context context, intent intent) {
        ...
    }
}
localreceiver localreceiver = new localreceiver();

//2. 注册广播
localbroadcastmanager.getinstance(context)
             .registerreceiver(localreceiver, new intentfilter(“test”));
//4. 发送广播
localbroadcastmanager.getinstance(context).sendbroadcast(new intent("test"));
//5. 取消注册广播
localbroadcastmanager.getinstance(context).unregisterreceiver(localreceiver);

自定义广播和普通的广播一样,在注册广播的时候将该广播接受者注册到localbroadcatmanager中。当发生时也是调用localbroadcastmanager的sendbroadcast进行发生。同样在不使用时记得取消广播注册。

2. localbroadcastmanager

2.1 初始化

localbroadcastmanager采用的是单例模式,其构造函数是私有的,获取该类实例的方法是getinstance,具体代码如下:

  private final handler mhandler;

    private static final object mlock = new object();
    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是主线程的
        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);
                }
            }
        };
    }

在构造函数中创建了一个mhandler,该mhandler关联的是主线程的looper。即消息处理时都在主线程中处理。

2.2 registerreceiver

public void registerreceiver(broadcastreceiver receiver, intentfilter filter) {
        //在注册,取消注册,发送广播的时候都需要先获取mreceivers的锁
        synchronized (mreceivers) {
            //新建一个receiverrecord实体表示该receiver及对应的filter
            receiverrecord entry = new receiverrecord(filter, receiver);
            //获取receiver对应的filters
            arraylist filters = mreceivers.get(receiver);
            if (filters == null) {
                //如果该receiver没有对应的filters则,新建一个。
                filters = new arraylist(1);
                mreceivers.put(receiver, filters);
            }
            //将filter放入该receiver对应的filters中
            filters.add(filter);
            for (int i=0; i entries = mactions.get(action);
                if (entries == null) {
                    entries = new arraylist(1);
                    //将action放入mactions中
                    mactions.put(action, entries);
                }
                entries.add(entry);
            }
        }
    }

注册的时候也就是将receiver自己和对应的filter及action放入到mreceivers和mactions当中。代码比较简单。

2.3 发送广播sendbroadcast

public boolean sendbroadcast(intent intent) {
        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 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);

            arraylist entries = mactions.get(intent.getaction());
            if (entries != null) {
                if (debug) log.v(tag, "action list: " + entries);

                arraylist receivers = null;
                for (int i=0; i<entries.size(); i++)="" {="" receiverrecord="" receiver="entries.get(i);" if="" (debug)="" log.v(tag,="" "matching="" against="" filter="" "="" +="" receiver.filter);="" (receiver.broadcasting)="" filter's="" target="" already="" added");="" }="" continue;="" int="" match="receiver.filter.match(action," type,="" scheme,="" data,="" categories,="" "localbroadcastmanager");="" (match="">= 0) {
                        if (debug) log.v(tag, "  filter matched!  match=0x" +
                                integer.tohexstring(match));
                        if (receivers == null) {
                            receivers = new arraylist();
                        }
                        receivers.add(receiver);
                        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);
                        }
                    }
                }

                if (receivers != null) {
                    for (int i=0; i

主要步骤:1.根据intent的action来查询相应的广播接收者列表; 2.创建相应广播,添加到mpendingbroadcasts队列; 3.发送msg_exec_pending_broadcasts消息。将消息传给主线程进行处理。 4.主线程mhandler接受到后就由该类的handlermessage进行处理。在该方法中调用executependingbroadcasts()进行处理

    private void executependingbroadcasts() {
        while (true) {
            broadcastrecord[] brs = null;
            synchronized (mreceivers) {//注意多线程下的同步
                final int n = mpendingbroadcasts.size();
                if (n <= 0) {
                    return;
                }
                brs = new broadcastrecord[n];
                mpendingbroadcasts.toarray(brs);//把待处理的广播转成数组形式
                mpendingbroadcasts.clear();//然后就可以把mpendingbroadcasts清空
            }
            //for循环变量每个接受者,然后调用对应的onreceive
            for (int i=0; i

处理也很简单,查询相应的变量,找到有多少个接受者,然后调用接受者的onreceive,该调用在主线程中,因而不要做耗时操作。在localbroadcastmanager中还提供了同步发送广播处理的方法:

    //使用该方法会立即去让接受者处理广播。
    public void sendbroadcastsync(intent intent) {
        if (sendbroadcast(intent)) {
            executependingbroadcasts();
        }
    }

2.4 广播的注销

 public void unregisterreceiver(broadcastreceiver receiver) {
        synchronized (mreceivers) {
            arraylist filters = mreceivers.remove(receiver);
            if (filters == null) {
                return;
            }
            for (int i=0; i receivers = mactions.get(action);
                    if (receivers != null) {
                        for (int k=0; k

注销广播也很简单,找到注册时候添加到list中的变量,然后remove掉。注意要讲mreceivers,mactions里面保存的都remove了。

3.总结

普通广播采用binder和系统通信,由ams进行管理,而应用内广播是通过handler的消息机制来进行通信,仅在一个进程中使用。和普通广播比,应用内广播安全,速度快。缺点是只能在应用的一个进程中使用,不能跨进程使用。

;>
();>