Handler 源码解析
2016-07-22 15:54
260 查看
Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Message message = handler.obtainMessage(); message.obj = "1"; handler.sendMessage(message);}
一、首先看Handler的初始化:
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper();
//Return the Looper object associated with the current thread.
// Returns null if the calling thread is not associated with a Looper.
if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
在上面的流程,已经为Handler准备好了Looper和MessageQueue。
默认的这个Handler 的构造器将Handler和Looper联系在一起(这样翻译有些奇怪),也是说一个Handler必须对应一个Looper。如果没有对应的Looper,则会抛出异常。其实还有Message、Message Queue,看了很多解释,我对这些概念的理解是:
Handler相当于搬运工,
搬运的货物是Message,
搬运目的地是Message Queue(消息队列)和主线程,
Looper是仓库管理员,支配Message Queue的出仓。
关于Looper、MessageQueue等对象的初始化,我们可以在下面找到。
Android应用程序进程在启动的时候,会在进程中加载ActivityThread类,并且执行这个类的main函数,应用程序的消息循环过程就是在这个main函数里面实现的,它定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:
public final class ActivityThread {
......
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
}
Handler初始化后,留了一个回调接口handleMessage(Message mes){};
二、Message
Message message = handler.obtainMessage();
/** * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this). * If you don't want that facility, just call Message.obtain() instead. */ public final Message obtainMessage() { return Message.obtain(this); }
如果不使用Message message = handler.obtainMessage()而重新new一个对象,需要将Message.target指向搬运工handler。
/** * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned. * @param h Handler to assign to the returned Message object's <em>target</em> member. * @return A Message object from the global pool. */ public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; }
三、 handler.sendMessage(message);
/** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
/** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
/** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be * delivered, using the * {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
//根据方法的名称,下面对Message进行入队排序。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null) { throw new AndroidRuntimeException("Message must have a target."); } synchronized (this) { if (mQuitting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
上面就是已经添加消息到队列头部的操作。 现在入队操作我们就已经看明白了,那出队操作是在哪里进行的呢。(但目前我还没有找到直接调用源码中Looper.looper())
在Looper类的有这么一段说明代码:
<pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
出队列应该有仓库管理员Looper来执行。
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final 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(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycle(); } }
msg.target.dispatchMessage(msg); Message中提到msg.target就是handler.
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
相关文章推荐
- wifi详解3
- android service不被kill的方法
- 推荐10 个短小却超实用的 JavaScript 代码段(http://www.jianshu.com/p/3ef822ec5a63)
- android 屏幕保持不锁屏
- Path Sum
- android动态屏幕适配(不需要多套图,多布局)
- 只有坚持还不够 为什么你的网站上不了百度首页
- Android自定义控件实现滑动开关效果
- android6.0系统Healthd深入分析
- linux脚本判断条件总结
- linux下如何查看系统和内核版本
- 搜索二叉树
- 你真的会用Gson吗?Gson使用指南(一)
- css3响应式布局
- 分布式系统间通信之RPC的基本概念(六)
- 使用JAVA客户端对HDFS进行代码编写(五)
- MVC 局部加载页面的实例
- 125. Valid Palindrome
- opengl颜色混合
- Android适配器中字体颜色设置无效解决