Android应用内广播LocalBroadcastManager机制
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的消息机制来进行通信,仅在一个进程中使用。和普通广播比,应用内广播安全,速度快。缺点是只能在应用的一个进程中使用,不能跨进程使用。
上一篇: UUID
下一篇: cdr怎么设计简易的易书架图形?
推荐阅读
-
Android应用内悬浮窗的实现方案示例
-
浅谈Android应用内悬浮控件实践方案总结
-
Android基于广播事件机制实现简单定时提醒功能代码
-
iOS和Android应用内消费持续走高:用户舍得花钱
-
Android广播接收机制详细介绍(附短信接收实现)
-
Android应用内悬浮窗的实现方案示例
-
一种 Android 应用内全局获取 Context 实例的装置
-
黑马Android76期学习笔记01基础--day08--start/bind开启服务、电话录音,特别广播接收者,bindService/接口调用服务内方法,混合开启服务,进程间通讯,aidl应用场景
-
Android数字签名机制和应用场景
-
Android 设置应用内字体不随系统的字体大小改变而改变