Handler源码分析原理
来源:互联网 发布:沈阳数据恢复 编辑:程序博客网 时间:2024/05/16 14:55
Handler产生的原因:
异步通信
因为Android只有在主线程才能进行UI操作(一般情况),而有很多情况下需要子线程去获取数据。由于俩个线程之间的不同步,所以子线程在获取数据后需要通知给主线程去改变UI;
那么怎么通知呢?即如何让主线程去调起改变UI的方法,而不是让子线程去调呢?(线程是抽象的概念,方法被哪个线程调起,就属于哪个线程,和代码中方法所写的位置无关,但是变量却是线程间共享的)
Handler从自我实现分析:
如下假设:A线程开启一个死循环,判断Boolean变量key是否为true,如果是true,执行某一方法;B线程可以在耗时操作结束后置key值为true;此时A检测到key为true,执行方法。
这样就实现了线程间的一个简单同步。
从Handler的使用中可以看出,Handler不仅仅是一个简单的通知,他还涉及到数据的传递。所以不能简单的用上述一个boolean判断来实现。但是思想是却是一致的。
Android中采用了MessageQueue作为这一Flag,即一旦消息队列中的消息不为空,主线程中已开启的死循环就取出消息,然后执行。这样就实现了从子线程到主线程的跨越。
但是很快问题就出现了,MessageQueue作为一个变量,是所有线程都能访问的。假如我们开启了另一个子线程,像主线程一样开启相同的死循环获取message,MessageQueue就会失去效果:
所以为了通用,我们必须实现一个线程一个MessageQueue副本,这样各自线程开启的死循环只会从各自的MessageQueue副本里拿,不会产生混乱,同时往MessageQueue里添加消息时,也要根据线程有选择的添加。ThreadLocal正好可以简单的实现不同线程不同数据副本的效果。(这里不深入ThreadLocal的实现)
最终的模型如下:
这样就实现了真正意义上的跨线程访问,而不局限与子线程与主线程。
Handler原理源码分析:
分析handler源码之前,离不开先分析Looper,所以先从looper的分析入手:
App主线程在启动时,首先会执行looper.parpare,源码如下:
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();}
可以看到,Looper初始化时新建了一个成员变量MessageQueue,然后连同messageQueue绑定给了ThreadLocal。下面看看ThreadLocal.set做了什么:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
可以看到,ThreadLocal把当前线程与该Looper对象关联在了一起,即,ThreadLocal把线程与其对应的MessageQueue做了关联,上述模型实现了第一步。
主线程在执行完Looper.parpare后,会执行Looper.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; ... for (;;) { Message msg = queue.next(); if (msg == null) { return; } ... } ... msg.target.dispatchMessage(msg); ... msg.recycleUnchecked(); } }
Looper.loop就是把之前parpare的MessageQueue进行了死循环,不断取出其消息,执行message.target.dispatchMessage(msg)方法!
至此,模型的后半部分(线程拥有各自的MessageQueue,并死循环取出执行)就完成了。现在只有俩个疑问,sendMessage是谁完成的?以及message.tartget又是谁?
这个时候,Handler终于登场了。首先看一下Handler初始化的源码:
public 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; }
可以看到,Handler拿到了一个Looper,换句话说,Handler拿到了一个MessageQueue,离sendMessage只差一步了!
但是根据模型,这个MessageQueue属于哪个线程的呢?换句话说,我们是往哪个线程sendMessage呢?
源码中Looper是通过myLooper得到的,看一下他的源码:
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
ThreadLocal又出现了,它的作用是取出对应线程的数据副本,这里就是取出对应线程的Looper(MessageQueue),分析一下它get()方法的源码:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
到这里一目了然,ThreadLocal取的就是当前线程之前所关联的Looper,也就是Handler初始化时所在线程的Looper!
所以Handler在初始化时,会获取Handler所在线程的Looper,同时获取该线程的MessageQueue。
最后一步,Handler.sendMessage(),sendMessage()最终会走到enqueueMessage()方法上:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
这里,msg.target终于有了赋值,就是Handler自己!
接着往下看,同样只保留了关键代码:
boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; } else { 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; } ... } return true; }
这部分仍然运行在子线程,通过sendMessage(msg)方法,给msg指定了其target为Handler本身,并将此msg加入到了messageQueue里。
所以:
handler.sendMessage()可以简单理解为 为Handler所在线程的MessageQueue添加Msg。
handler.sendMessage()运行在线程B,只是添加msg数据。真正操作msg数据的方法,运行在Handler所在线程A里,以此实现跨线程。
Handler原理简化模型:
最后需要说明一下,只有主线程默认执行了Loop.parpare()和Looper.loop(),其它线程想要跨线程需要手动执行。
- Handler源码分析原理
- Handler源码原理分析
- handler机制原理源码分析
- Handler原理讲解及源码分析
- Android 5.0 源码分析 Handler Looper MessageQueue 底层原理
- Android源码分析--Handler机制的实现与工作原理
- 最简洁的Handler、Looper、Message源码级原理分析
- Handler,Looper 原理分析
- Handler原理分析
- Android Handler原理分析
- Handler原理分析
- Handler原理分析
- handler的原理分析
- Handler 源码分析
- Handler的源码分析
- Looper、Handler源码分析
- Handler源码分析
- [Android源码]Handler分析
- js之constructor属性/instanceof运算符/原型的理解
- find常用操作总结
- 欢迎使用CSDN-markdown编辑器
- 初篇
- Linux目录结构
- Handler源码分析原理
- composer 正确使用
- URL 和 URI 有什么不同?
- Linux
- tuxera怎么帮助Mac传输文件
- Qsee指纹数据dump方法
- Android Design Support Library使用详解
- 【慕课网_性能优化之MySQL优化_学习】【11】
- 数据结构第五版第一章上机实验题2