Handler源码原理分析
2017-11-19 23:52
141 查看
Android 系统内部是消息机制,什么意思?
说说Handler运行机制?
Handler功能定义:各线程互相通讯用的。常用子线程在做完某事之后然后去更新UI之类。当然两个子线程也能用Handler相互通讯。
本文主要分析两个线程是怎么通信的?通过源码分析原理是什么?
子与主线程通讯用法:
子与子线程通讯用法:
发送时不变,还是用handler对象直接发送空消息,或者创建消息发送。
就多了
需要分析的类
Message:消息对象,用到存放数据,和下一个Message对象
MessageQueue:字面意思消息队列,但其实它并不是队列,不过确实是负责消息的插入和取出
Handler:给用户层用来创建和发送消息,和处理收到的消息
Looper:不断循环取消息,和调用Handler处理消息
(说实话,这种看别人简单的总结根本不能理解,肯定想问,这到底是Handler发送处理消息,还是Looper发送处理消息?等等疑问。这都个人理解,还是看源码说吧)
先来看传递的对象Message,有几个常用属性。
然后直接进Handler 类
可以看到,不管是
观察到mQueue是从Looper中拿来的,如果Looper为空,就
看sThreadLocal赋值
直接在初始化就定义了,并且static final,说明一个进程只有一个,并无再赋值,然后看ThreadLocal是什么?
ThreadLocal 定义:与线程想关的数据存储类。
ThreadLocal 使用
用法简单。只有get、set、remove。可以看到,主线程set(true),get()是true。在子线程中,第一次get,因为没有set,直接为null。然后set(false),取出false,说明在子线程中,并没有get到主线程set的值。看看实现:
Values 为ThreadLocal 的静态内部类,可以看到,数据最终存储的地方在Thread对象本身里的localValues.table数组里,ThreadLocal只是判断线程,然后把数据有序在放在table里,这里用了一个高效存储算法,table[i]为key,[i+1]为value,大概就是这样意思,这样可能效率性能会好吧!
如果Thread对象本身Values存储怎么办?实现这个和线程相关的存储数据有很多方法,自己也可以实现,下面自己实现一个:
用线程唯一标识为Key就行,效率可能没google写的ThreadLocal好。
再回到Looper.myLooper()方法。
这里线程取到的肯定为空,唯一赋值方法在
所以我们在子线程初始化Handler时,才要
可以看到,有熟悉的java的main,
Ok,创建了Looper,创建了
这里可以看到,当前msg是赋值给最后一个msg的next,这里像是单链表。如图:
![](https://img-blog.csdn.net/20171119224810039?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDUyMTY0NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
Message mMessages;即是链表第一个msg,也就是最快将要处理的msg(如果不为空的话)
这里有两种情况,else表示链表不为空,通过for循环,定位到最后一个msg,然后把新传递进来的msg赋值给最后一个msg的next。这就算是添加成功了。if表示链表为空(如果你进入一个新页面,不做任何操作,msg队列将会被处理完,然后主线程会睡眠,当有新的msg进来时,要唤醒主线程)
到此,msg就算是添加到队列中了,然后在哪里处理呢?
这就要看ActivityThread中main方法最后调用了
简单理解就是循环从
如果msg有
然后重点看
大致为
而且我们还发现
总结:
说说Handler运行机制?
Handler功能定义:各线程互相通讯用的。常用子线程在做完某事之后然后去更新UI之类。当然两个子线程也能用Handler相互通讯。
本文主要分析两个线程是怎么通信的?通过源码分析原理是什么?
子与主线程通讯用法:
Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch(msg.what){ case 100: String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj; mTextView.setText(s); Logger.d(s); break; default: break; } } }; .... new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); mHandler.sendEmptyMessage(100); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();
子与子线程通讯用法:
new Thread("thread2"){ public void run() { Looper.prepare(); mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj; Logger.d(s); } }; Looper.loop(); } }.start();
发送时不变,还是用handler对象直接发送空消息,或者创建消息发送。
就多了
Looper.prepare()和
Looper.loop();等下会讲为什么。
需要分析的类
Message:消息对象,用到存放数据,和下一个Message对象
MessageQueue:字面意思消息队列,但其实它并不是队列,不过确实是负责消息的插入和取出
Handler:给用户层用来创建和发送消息,和处理收到的消息
Looper:不断循环取消息,和调用Handler处理消息
(说实话,这种看别人简单的总结根本不能理解,肯定想问,这到底是Handler发送处理消息,还是Looper发送处理消息?等等疑问。这都个人理解,还是看源码说吧)
先来看传递的对象Message,有几个常用属性。
**Message.class** public int what; //区分消息的标识,在发送消息和接收时确认 public int arg1,arg2; //可以传递两个int值 public Object obj; //其它想要传递的对象
然后直接进Handler 类
mHandler.sendEmptyMessage(100);看看发送时做了什么。
**Handler.class** public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg,0); } ... //延迟多少毫秒发送 public final boolean sendMessageDelayed(Message msg,long delayMillis){ if(delayMillis< 0){ delayMillis=0; } // SystemClock.uptimeMillis()系统开机时间 return sendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis); } //在一个准确时间发送 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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
可以看到,不管是
sendMessage,还是
sendMessageDelayed等……最后都是调用了
sendMessageAtTime,然后
enqueueMessage,又分发给了
queue.enqueueMessage(msg, uptimeMillis),然后发现有个
MessageQueue queue,看在哪赋值?在Handler构造函数中,Handler构造函数也很多,最终进:
**Handler.class** 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; }
观察到mQueue是从Looper中拿来的,如果Looper为空,就
throw new RuntimeException(),那进
Looper.myLooper();
**Looper.class** public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
看sThreadLocal赋值
**Looper.class** // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
直接在初始化就定义了,并且static final,说明一个进程只有一个,并无再赋值,然后看ThreadLocal是什么?
ThreadLocal 定义:与线程想关的数据存储类。
ThreadLocal 使用
ThreadLocal<Boolean> mThreadLocal=new ThreadLocal<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mThreadLocal.< ef6a span class="hljs-keyword">set(true); Logger.d(Thread.currentThread() + " " + mThreadLocal.get()); new Thread(new Runnable() { @Override public void run() { Logger.d(Thread.currentThread() + " " + mThreadLocal.get()); mThreadLocal.set(false); Logger.d(Thread.currentThread() + " " + mThreadLocal.get()); } }).start(); } **log** D/: Thread[main,5,main] true D/: Thread[Thread-221,5,main] null D/: Thread[Thread-221,5,main] false
用法简单。只有get、set、remove。可以看到,主线程set(true),get()是true。在子线程中,第一次get,因为没有set,直接为null。然后set(false),取出false,说明在子线程中,并没有get到主线程set的值。看看实现:
**ThreadLocal.class** public class ThreadLocal<T> { public T get() { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); } public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); } ... Values values(Thread current) { return current.localValues; } static class Values { private Object[] table; } }
Values 为ThreadLocal 的静态内部类,可以看到,数据最终存储的地方在Thread对象本身里的localValues.table数组里,ThreadLocal只是判断线程,然后把数据有序在放在table里,这里用了一个高效存储算法,table[i]为key,[i+1]为value,大概就是这样意思,这样可能效率性能会好吧!
如果Thread对象本身Values存储怎么办?实现这个和线程相关的存储数据有很多方法,自己也可以实现,下面自己实现一个:
//自己写的ThreadLocal public class ThreadLocal<V> { private Map<Long,V> mMap; public ThreadLocal() { mMap = new HashMap<>(); } public V get(){ long id = Thread.currentThread().getId(); return mMap.get(id); } public void put(V value){ long id = Thread.currentThread().getId(); mMap.put(id,value); } }
用线程唯一标识为Key就行,效率可能没google写的ThreadLocal好。
再回到Looper.myLooper()方法。
**Looper.class** public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
这里线程取到的肯定为空,唯一赋值方法在
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)); }
所以我们在子线程初始化Handler时,才要
Looper.prepare();为了实例化Looper,而且每个线程还只能调用一次,那我们的主线程在那调用的呢?那就要到ActivityThread.class看看了,ActivityThread就是每个应用的大门,应用的main函数。activity、service、broadcasts等都是在这里启动。
public final class ActivityThread { ... public static void main(String[] args) { ...省略代码若干 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } ... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } final Handler getHandler() { return mH; } }
可以看到,有熟悉的java的main,
new Handler()之前调用
Looper.prepareMainLooper();这个内部也是
prepare(),而且这个Handler处理这个应用系统所有Message,Activity生命周期、createService等都是这个handler进行分发。这个类以后要好好研究,所以为什么这就是android系统内部的消息机制,无论点击按钮,启动页面,都是通过Handler进行发送消息然后分发到各个类处理。
Ok,创建了Looper,创建了
MessageQueue,然后看
MessageQueue的
enqueueMessage方法
boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... msg.markInUse(); msg.when = when; Message p = mMessages;//单链表的第一个message boolean needWake;//是否需要唤醒,如果链表中没有待处理的message,主线程将睡眠 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked;//上一个message为空,说明这是要处理message队列的第一个,将唤醒主线程,这里会为true } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); //这一段逻辑是取出链表中的最后一个Message prev,把新的msg赋值给它的next 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);//为true,将唤醒主线程 } } return true; }
这里可以看到,当前msg是赋值给最后一个msg的next,这里像是单链表。如图:
Message mMessages;即是链表第一个msg,也就是最快将要处理的msg(如果不为空的话)
这里有两种情况,else表示链表不为空,通过for循环,定位到最后一个msg,然后把新传递进来的msg赋值给最后一个msg的next。这就算是添加成功了。if表示链表为空(如果你进入一个新页面,不做任何操作,msg队列将会被处理完,然后主线程会睡眠,当有新的msg进来时,要唤醒主线程)
nativeWake(mPtr);是个native方法,唤醒主线程。
到此,msg就算是添加到队列中了,然后在哪里处理呢?
这就要看ActivityThread中main方法最后调用了
Looper.loop();因为这个会阻塞线程,所以要放在线程最后调用。
public static void loop() { final Looper me = myLooper(); ... final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } 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); } ... } }
简单理解就是循环从
MessageQueue中
next();方法取msg,为空将结束循环,否则
msg.target.dispatchMessage(msg);这里
msg.target就是创建msg时的handler,进
dispatchMessage方法。
**Handler.class** public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
如果msg有
callback,这个callback是
Runnable,否则检查
mCallback不为空,调用
mCallback.handleMessage(msg),最后调用自身的
handleMessage(msg);,我们一般都是直接
new Handler(),重写
handleMessage(msg)方法。可以看见传递
callback也是可以的。这里比较简单。
然后重点看
queue.next(),也就是取出msg方法
**MessageQueue.class** Message next() { int nextPollTimeoutMillis = 0; for (; ; ) { ... nativePollOnce(ptr, nextPollTimeoutMillis); ... synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; ... if (msg != null) { // Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; msg.markInUse(); return msg; } else { // No more messages. nextPollTimeoutMillis = -1; } ... } } }
大致为
mMessages是否为空,不为空就把
return mMessages出去,并且
next标记清掉,给
mMessages = msg.next;赋于下一个msg。为空的话
nextPollTimeoutMillis = -1;下次循环中,
nativePollOnce(ptr, nextPollTimeoutMillis);为-1时将睡眠。
而且我们还发现
Printer logging = me.mLogging;会调用
Printer.println(String n),说明我们可以监听到msg的处理,例:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Looper.myLooper().setMessageLogging(new Printer(){ @Override public void println(String x) { Log.d("TAG",x); } }); Looper.myLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() {//消息队列处理完毕回调,return false 将只能监听一次结束 return true; } }); }
addIdleHandler可以监听消息队列处理完毕,
setMessageLogging可以监听消息处理前后,打打log:
D/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0 D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179: 0 D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179 D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1f: 0 D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1f D/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 101 D/: <<<<< Finished to Handler (android.app.ActivityThread$H) {b0be8e6} null D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} null: 6 D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} null D/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0 D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f D/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 100
总结:
Handler消息机制就是,主线程不断循环(
Looper.loop)检查有无待处理msg(
queue.next),有就处理(
handler.dispatchMessage()),没有就睡眠(
nativePollOnce())。当子线程发送了一个msg时(
queue.enqueueMessage),唤醒主线程(
nativeWake()),主线程就接着处理(
queue.next),从而实现了子线程与主线程通信。原理也就是子线程与主线程共同操作一个队列,一存,一取。原理简单粗暴,不过
nativePollOnce睡眠、
nativeWake唤醒、两个为native方法,肯定不是sleep那么简单。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析