为什么?
多问为什么是解决并理解问题的最好的办法,Handler是Android SDK中的类,Android为什么要引入Handler、Looper、MessageQueue呢?
线程间通讯,消息队列处理
经常使用的场景有通过Handler更新UI,貌似我们理解中更新UI只能在主线程 这句话好像是对的,其实更准确的说法是更新UI只能在UI线程,即要更新的UI所在ViewRoot创建时候的线程,如果当前ViewRoot是在子线程创建的,更新ViewRoot里面的UI必须在这个子线程中更新,而我们常见的ViewRoot创建都是在主线程,所以把常见的结果当成标准结果是万万不可的。
为什么采用消息队列的形式呢?消息队列的方式可以解决线程堵塞数据混乱等问题。言归正传
Handler
Handler是用来发送和处理消息的
Handler对象的创建需要绑定一个指定线程的Looper, 即Handler是和线程相关的,如一个Handler绑定的是一个子线程中的Looper,那么这个Handler就不能用来更新UI线程(主线程)。Looper
Looper是通过for (;;)
循环来不停的把MessageQueue中的消息交给Handler处理
MessageQueue
用来存储Message的消息队列
源码分析(类分析)
Handler的构造函数中只有2个基本构造函数
1.未指定Looperpublic Handler(Callback callback, boolean async) { //省略部分代码 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; mAsynchronous = async; }复制代码
2.指定Looper
public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }复制代码
其中未指定Looper通过mLooper = Looper.myLooper();
来获取当前线程中的Looper
Looper.myLooper();
究竟做了哪些操作 ,打开Looper
源码 public static @Nullable Looper myLooper() { return sThreadLocal.get(); }复制代码
额。。。sThreadLocal
是什么鬼,怎么通过他返回一个Looper
继续查看
static final ThreadLocalsThreadLocal = new ThreadLocal ();复制代码
原来是一个ThreadLocal
ThreadLocal用于保存某个线程共享变量,当前即为保存线程中Looper
变量,通过sThreadLocal
来获取当前线程的Looper
,在过sThreadLocal
没有进行set()
的时候sThreadLocal.get()
为空,为空的时候
if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }复制代码
会提示RuntimeException
提示我们在创建对象之前必须先执行Looper.prepare()
ActivityThread
的main
方法中已经执行过Looper.prepareMainLooper();
所以不需要我们执行,系统已经帮我们执行过了 而在子线程中创建Handler 或指定的子线程中的Looper,必须我们手动执行Looper.prepare()
不然就会报RuntimeException
异常信息 继续查看Looper.prepare()
执行了哪些操作 public static void prepare() { prepare(true); }private static void prepare(boolean quitAllowed) { //如果已经存在了Looper也会报异常 所以Looper.prepare()只能必须执行1次 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //保存在sThreadLocal中 sThreadLocal.set(new Looper(quitAllowed)); }复制代码
继续看new Looper(quitAllowed)
的处理
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }复制代码
创建MessageQueue对象 绑定当前线程
小结
自此三者的关系明朗了起来
Handler绑定了Looper,Looper创建了一个MessageQueue对象 Handler拥有Looper、MessageQueue成员变量源码分析(如何发处理消息)
通过层层跳转,发送消息都会执行到sendMessageAtTime
方法中
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); }复制代码
也就是enqueueMessage(queue, msg, uptimeMillis)
方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { //设置msg的target为当前Handler msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }复制代码
这里主要就是设置msg的target为当前Handler然后调用MessageQueue的enqueueMessage(msg, uptimeMillis)
方法把此msg存储到消息队列中
Looper.loop()
方法登场了 public static void loop() { //省略部分代码 for (;;) { Message msg = queue.next(); // might block //省略部分代码 try { //执行msg的target(Handler)的dispatchMessage方法 msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } //省略部分代码 } }复制代码
原来for循环不停的取出msg执行msg对于的Handler中的dispatchMessage(msg)
方法
public void dispatchMessage(Message msg) { //如果msg创建的时候设置了callback则会执行callback的run方法 if (msg.callback != null) { handleCallback(msg); } else { //如果在创建Handler的时候设置了callback则会执行callback的handleMessage方法 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //都没有设置则会执行Handler的handleMessage方法 handleMessage(msg); } }复制代码
至此 Handler的发送与消息处理整个流程就解析完毕
总结
线程中使用Handler步骤
1.Looper.prepare()
准备Looper(主线程已经在ActivityThread中执行); 2.new Handler()
创建Handler(注意指定的Looper线程或创建对象所在的线程) 3.Looper.loop()
启动Looper 循环取出MessageQueue中的消息交给Handler处理(主线程已经在ActivityThread中执行) 发送消息流程
1.Handler.sendMessageAtTime()
定时发送消息 2.MessageQueue.enqueueMessage()
存储消息至消息队列 3.Handler.dispatchMessage(msg);
消息的分发处理