Handler任务模型之MessageQueue
2015-10-23 22:36
399 查看
1. 介绍
在之前的篇幅中介绍了Handler任务模型中Message类和Looper类的源码分析,本篇将分析Handler类和Message类。
2. 源码分析
Handler类
之前 Handler任务模型之Looper类分析得到博乐评论说应该从使用开始到源码分析,这样可以使条理更加清晰,所以咱们先看下Handler的使用
我们一般是这样使用Handler的,首先谈下Handler的构造,Handler类本身提供了四种构造方法
四种构造函数主要是为了三个变量赋值,第一个是mLooper,第二个是mQueue,第三个是mCallBack。
其中Looper是一个循环体,MessageQueue保持着Message消息链的引用,mCallBack提供一个回调方法在handlerMessage之前执行。
Handler类本身提供了很多的发送消息的方法和post的方法
这些方法内部最后都是同一调用sendMessageAtTime这个方法
第6行:将Message的target赋值为this,可以看出一个Message对应一个Handker,谁发送的消息还要交给谁处理,只是在主线程绕一圈而已
第7行:将msg投递到消息链中
MessageQueue源码分析
handler的sendMessageAtTime方法内部调用MessageQueue的enqueueMessage投递任务
第2-5行:通过msg.when对消息进行校验,新消息默认是没有when赋值的,如果此时msg.when != 0说明已经执行该Message正在被使用。不能再次被添加到链表中去
第6-8行:在之前的篇幅中我们介绍过当msg.target为空作为Looper消息循环结束的一个标志位,
mQuitAllowed控制当前线程是否被允许,一般线程是被允许,因为mQuitAllowed初始值为true,但是UI主线程是不允许退出的,因为在Looper的prepareMainLooper方法中将mQuitAllowed赋值为false
第20 - 37行:在Message源码分析中我们可以看出Message是以链表形式存放的,当时不能看出Message之间的关系,其实Message是一个按照时间从小到大的链表形式存放的,这些代码行就是处理这些逻辑关系。
通过上面的步骤已经将Message添加消息链表中,同时Looper的loop方法会一直调用MessageQueue的next取出消息
第11-28行:通过判断时间是否符合条件从链表中取出消息,这里时间是按照开机时间计算的
余下的代码行是处理IdleHandler闲时回调接口,以及该回调接口是处理一次即焚还是继续调用的问题,
好像在项目中不是很常用到。
这样从MessageQueue持有的消息链中取出消息后就要回到Looper的loop方法逻辑
第16-19行:通过标志位控制Looper的退出
第20行:分发消息msg.target.dispatchMessage(msg);
这样就将消息分发给相应的Handler中,最后回调到我们重写的handleMessage方法中
3. 总结
从以上的分析我们可以看出,各个类之间的对应关系,一个Thread对应一个Looper,一个Looper对应一个MessageQueue,一个MessageQueue持有一个Message消息链,消息链中每个消息对应一个Handler,也就是一个Looper对应对个Handler对象。
在之前的篇幅中介绍了Handler任务模型中Message类和Looper类的源码分析,本篇将分析Handler类和Message类。
2. 源码分析
Handler类
之前 Handler任务模型之Looper类分析得到博乐评论说应该从使用开始到源码分析,这样可以使条理更加清晰,所以咱们先看下Handler的使用
private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { //................. }; };
Message msg = Message.obtain(); msg.what = 0; handler.sendMessage(msg);
我们一般是这样使用Handler的,首先谈下Handler的构造,Handler类本身提供了四种构造方法
public Handler() { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null; }
public Handler(Callback callback) { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; }
public Handler(Looper looper) { mLooper = looper; mQueue = looper.mQueue; mCallback = null; }
public Handler(Looper looper, Callback callback) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; }
四种构造函数主要是为了三个变量赋值,第一个是mLooper,第二个是mQueue,第三个是mCallBack。
其中Looper是一个循环体,MessageQueue保持着Message消息链的引用,mCallBack提供一个回调方法在handlerMessage之前执行。
Handler类本身提供了很多的发送消息的方法和post的方法
这些方法内部最后都是同一调用sendMessageAtTime这个方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }
第6行:将Message的target赋值为this,可以看出一个Message对应一个Handker,谁发送的消息还要交给谁处理,只是在主线程绕一圈而已
第7行:将msg投递到消息链中
MessageQueue源码分析
handler的sendMessageAtTime方法内部调用MessageQueue的enqueueMessage投递任务
final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } final boolean needWake; synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.target == null) { mQuiting = true; } msg.when = when; //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; // new head, might need to wake up } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; needWake = false; // still waiting on head, no need to wake up } } if (needWake) { nativeWake(mPtr); } return true; }
第2-5行:通过msg.when对消息进行校验,新消息默认是没有when赋值的,如果此时msg.when != 0说明已经执行该Message正在被使用。不能再次被添加到链表中去
第6-8行:在之前的篇幅中我们介绍过当msg.target为空作为Looper消息循环结束的一个标志位,
mQuitAllowed控制当前线程是否被允许,一般线程是被允许,因为mQuitAllowed初始值为true,但是UI主线程是不允许退出的,因为在Looper的prepareMainLooper方法中将mQuitAllowed赋值为false
public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } }
第20 - 37行:在Message源码分析中我们可以看出Message是以链表形式存放的,当时不能看出Message之间的关系,其实Message是一个按照时间从小到大的链表形式存放的,这些代码行就是处理这些逻辑关系。
通过上面的步骤已经将Message添加消息链表中,同时Looper的loop方法会一直调用MessageQueue的next取出消息
final Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); final Message msg = mMessages; if (msg != null) { final long when = msg.when; if (now >= when) { mBlocked = false; mMessages = msg.next; msg.next = null; if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg); return msg; } else { nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); } } else { nextPollTimeoutMillis = -1; } // If first time, then get the number of idlers to run. if (pendingIdleHandlerCount < 0) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount == 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; }
第11-28行:通过判断时间是否符合条件从链表中取出消息,这里时间是按照开机时间计算的
余下的代码行是处理IdleHandler闲时回调接口,以及该回调接口是处理一次即焚还是继续调用的问题,
好像在项目中不是很常用到。
这样从MessageQueue持有的消息链中取出消息后就要回到Looper的loop方法逻辑
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } msg.target.dispatchMessage(msg); msg.recycle(); } } }
第16-19行:通过标志位控制Looper的退出
第20行:分发消息msg.target.dispatchMessage(msg);
这样就将消息分发给相应的Handler中,最后回调到我们重写的handleMessage方法中
3. 总结
从以上的分析我们可以看出,各个类之间的对应关系,一个Thread对应一个Looper,一个Looper对应一个MessageQueue,一个MessageQueue持有一个Message消息链,消息链中每个消息对应一个Handler,也就是一个Looper对应对个Handler对象。
相关文章推荐
- iOS -UIColor随机生成颜色的方法
- NGUI入门学习笔记
- 01-复杂度2 Maximum Subsequence Sum (25分)
- CoreBluetooth的实现代码
- UIView笔记
- NSOPeration 之UItabView无沙盒缓存——UITabView下载图片后 从操作缓冲池清除下载操作
- java.sql.SQLException: Can not issue empty query.
- GUI.tooltip
- UITableView
- CGContextRef CGMutablePathRef UIBezierPath
- NSOperation之为UItabView制作图片缓存——在didReceiveMemoryWarning方法中做图片缓存的清理操作
- UI中涉及到定时器的显示
- N-Queens and N-Queens II
- iOS笔记UI--UILabel
- poj 1141 Brackets Sequence(区间DP记录路径)
- hdoj--2767--Proving Equivalences (scc+缩点)
- hdoj--2767--Proving Equivalences (scc+缩点)
- [sicily]1388. Quicksum
- priority_queue
- java中的StringBuffer类和StringBuilder类