读Handler 源码之浅析
来源:互联网 发布:网页预览pdf的js插件 编辑:程序博客网 时间:2024/05/29 03:32
Handler的东西网上的资料一大堆,自己也看了不少,相关的知识点也已经很熟悉了。但是总感觉少点什么,没错,就是源码。好好的阅读一下源码对自己的成长还是很有好处的。
本文按照如下的几个方面来阅读源码:
1)Looper.prepare();
new Handler(...);
Looper.loop();
这背后都做了哪些工作?
2)消息的发送
3)消息的分发
首先看第一个问题:在非UI线程如果想要使用Handler,就必须添加Looper.prepare();和Looper.loop();这两段代码。这两段代码做了啥?请看源码:
public static void prepare() { prepare(true);}
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));}
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}
关于ThreadLocal的资料网上一大堆,自己可以学习一下,说白了ThreadLocal可以为当前的线程保存一个单独的副本。如上述源码,我们可以看到prepare为我们做了如下的工作:
1、判断当前线程是不是已经有Looper了,如果有则抛出异常;
2、将Looper保存到当前的线程ThreadLocal.ThreadLocalMap中;
除此之外,生成Looper对象的时候也生成了消息队列,这个消息队列就是消息的存放、遍历的数据结构。
接着看new 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 = callback;首先,从当前线程取出Looper,拿到了Looper就拿到了MessageQueue,至于mCallBack则是Handler暴露给我们的一个接口,可以作为初始化Handler的一个参数。到目前为止,Handler拿到了Looper、MessageQueue这两个最重要的东西了。
最后,Looper.Loop()的源码在(2)(3)之后在说明,Looper.Loop()的作用就是做好了从MessageQueue的准备,并在MessageQueue有消息的时候,取出消息并交给Handler处理 。
万事俱备,现在可以发送消息了,消息的发送最终都是调用的如下的代码:
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);}这个mQueue是什么呢?就是Looper为我们准备的消息队列,有了这个队列,我们就可以将发送的消息排队存放到这个消息队列,等待Hanlder处理了。
好了,现在消息也发送了,并且也保存到了消息队列了,怎么取呢?这就是Looper.Loop()的工作了。看Loop()方法的源码(紧摘取关键的部分):
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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } }
我们可以看到,Loop()方法主要是一个for(;;),这意味Looper会不断的遍历MessageQueue,只要有消息就会取出来(Message msg = queue.next()),然后交给Hanlder进行处理( msg.target.dispatchMessage(msg);)。问题来了,我们怎么知道要交给哪个Handler来处理呢?这就要看消息是怎么被放到MessageQueue了,如下所示:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
最关键的是第一行:msg.target = this。这个this是什么呢?没错,就是handler。
好了,知道将消息交给谁处理了,但是到底是怎么处理的呢?其实关键点就是: msg.target.dispatchMessage(msg);先看源码:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
首先,msg.callback是什么呢?还记得handler的post方法吧?这个post的参数是一个Runnable,这个callback就是我们post的Runnable。其次,mCallback是什么呢?其实就是我们在Handler构造函数中传递的CallBack接口。最后,handleMessage就是我们普通的Message了。
----------------------------------------------------------------------------------------------
关于Looper还需注意:在子线程中,如果手动的为其创建Looper,那么所有的事情处理完毕之后,应该调用quit方法来终止消息循环,否则子线程就会一直处于等待状态,如果退出Looper,那么子线程就会立即终止,因此建议在不需要的时候终止Looper
- 读Handler 源码之浅析
- Android Handler源码浅析
- handler源码浅析
- 源码简读之Handler
- 读AtomicBoolean源码之浅析
- 读AsyncTask源码之浅析
- Android开发之Handler浅析
- 源码浅析: Message/Handler/MessageQueue/Looper
- 源码浅析: Message/Handler/MessageQueue/Looper
- Android源码浅析: Message/Handler/MessageQueue/Looper
- 源码学习之Handler
- Android FrameWork源码浅析之(一)--handler,looper,messagequeue
- 读IntentService、HandlerThread源码之浅析
- android之Handler消息机制浅析
- Handler浅析
- 浅析android中handler与Message(二)+源码查看器
- Handler、Message、MessageQueue、Looper调用过程源码浅析
- Handler、MessageQueue、Runnable与Looper的源码浅析
- C++实验4-输出星号图
- c++第四次上机实验
- git的基本使用
- poj 2503 Trie模板
- 虚拟机有关操作脚本
- 读Handler 源码之浅析
- C++实验5——求和
- 557. Reverse Words in a String III
- GAT项目新需求:保险管理修改
- phongap、APICloud、ionic等app开发平台你都知道吗?
- 拉普拉斯近似算法小结
- 读文件常用方法
- ZooKeeper的安装与部署
- 339. Nested List Weight Sum