说说Android的广播(2) - 并发队列和串行队列
2016-06-06 19:14
309 查看
并发队列和串行队列
前面我们讲了,消息分为普通消息和有序消息两大类。普通消息是可以并发的,由于是并发的,这些广播的处理者之间互相是不依赖的。另外,并发队列和串行队列都各维护了一条后台广播队列和前台广播队列。如果这个消息足够重要,想走快速通道的话,可以选择使用前台广播队列。
对于并发队列,如果是进程活着,动态注册到队列里的,系统会通过并发的方式迅速将消息广播出去,就跟大家所想象的一样。
但是如果需要通过启动新进程才能处理消息的情况,为了避免同时启动大量进程,系统还是采用串行的方式来处理的。后面我们会分析这个过程的细节。
我们先来看一张思维导图来个整体的印象:
队列的定义
这两个队列定义于frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java中/** * Lists of all active broadcasts that are to be executed immediately * (without waiting for another broadcast to finish). Currently this only * contains broadcasts to registered receivers, to avoid spinning up * a bunch of processes to execute IntentReceiver components. Background- * and foreground-priority broadcasts are queued separately. */ final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>(); /** * List of all active broadcasts that are to be executed one at a time. * The object at the top of the list is the currently activity broadcasts; * those after it are waiting for the top to finish. As with parallel * broadcasts, separate background- and foreground-priority queues are * maintained. */ final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
前台队列和后台队列
在发送广播时,可以通过设置Intent.FLAG_RECEIVER_FOREGROUND属性来指定使用前台队列。ActivityManagerService中直接就定义了两个BroadcastQueue:
440 BroadcastQueue mFgBroadcastQueue; 441 BroadcastQueue mBgBroadcastQueue; 442 // Convenient for easy iteration over the queues. Foreground is first 443 // so that dispatch of foreground broadcasts gets precedence. 444 final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
如何获取这个队列呢,AMS中提供了broadcastQueueForIntent方法,很简单,就是判断Intent.FLAG_RECEIVER_FOREGROUND啦:
446 BroadcastQueue broadcastQueueForIntent(Intent intent) { 447 final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0; 448 if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST, 449 "Broadcast intent " + intent + " on " 450 + (isFg ? "foreground" : "background") + " queue"); 451 return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue; 452 }
如何加入到广播队列中
BroadcastQueue中定义了enqueueParallelBroadcastLocked方法,可以将BroadcastRecord对象加入到并发队列中。public void enqueueParallelBroadcastLocked(BroadcastRecord r) { mParallelBroadcasts.add(r); r.enqueueClockTime = System.currentTimeMillis(); }
当然,也有对应的串行队列的入队列方法:
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) { mOrderedBroadcasts.add(r); r.enqueueClockTime = System.currentTimeMillis(); }
BroadcastRecord
不管是并发队列还是串行队列,都是BroadcastRecord对象的ArrayList。所有后面对这个队列的处理,都是基于这里面的对象。大部分的字段看起来都是蛮眼熟的哈,基本上上面我们写代码时传进来的,取一个公共集,可以适用于三种大的消息类型。final class BroadcastRecord extends Binder { final Intent intent; // the original intent that generated us final ComponentName targetComp; // original component name set on the intent final ProcessRecord callerApp; // process that sent this final String callerPackage; // who sent this final int callingPid; // the pid of who sent this final int callingUid; // the uid of who sent this final boolean ordered; // serialize the send to receivers? final boolean sticky; // originated from existing sticky data? final boolean initialSticky; // initial broadcast from register to sticky? final int userId; // user id this broadcast was for final String resolvedType; // the resolved data type final String[] requiredPermissions; // permissions the caller has required final int appOp; // an app op that is associated with this broadcast final BroadcastOptions options; // BroadcastOptions supplied by caller final List receivers; // contains BroadcastFilter and ResolveInfo IIntentReceiver resultTo; // who receives final result if non-null long enqueueClockTime; // the clock time the broadcast was enqueued long dispatchTime; // when dispatch started on this set of receivers long dispatchClockTime; // the clock time the dispatch started long receiverTime; // when current receiver started for timeouts. long finishTime; // when we finished the broadcast. int resultCode; // current result code value. String resultData; // current result data value. Bundle resultExtras; // current result extra data values. boolean resultAbort; // current result abortBroadcast value. int nextReceiver; // next receiver to be executed. IBinder receiver; // who is currently running, null if none. int state; int anrCount; // has this broadcast record hit any ANRs? BroadcastQueue queue; // the outbound queue handling this broadcast static final int IDLE = 0; static final int APP_RECEIVE = 1; static final int CALL_IN_RECEIVE = 2; static final int CALL_DONE_RECEIVE = 3; static final int WAITING_SERVICES = 4; // The following are set when we are calling a receiver (one that // was found in our list of registered receivers). BroadcastFilter curFilter; // The following are set only when we are launching a receiver (one // that was found by querying the package manager). ProcessRecord curApp; // hosting application of current receiver. ComponentName curComponent; // the receiver class that is currently running. ActivityInfo curReceiver; // info about the receiver that is currently running.
发送消息
只放到广播队列里面还只是第一步,我们还需要通过消息队列将消息发送出去。mBroadcastsScheduled用来标识发送的状态,如果已经处于此状态,就直接返回。如果没有发送,就发送一条BROADCAST_INTENT_MSG消息出去。
public void scheduleBroadcastsLocked() { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); if (mBroadcastsScheduled) { return; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; }
这个方法对于并发队列和串行队列都是一样的。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories