咱们平时在开发中,常常用到Handler,用来发送消息,处理消息。 或者作一些延迟发送消息,跨线程发消息,或者更新UI,或者去实现一些定时轮询的操做。 安卓发展至今,已经有不少框架,能够代替这样原生Handler的通讯方式。 好比Eventbus, Rxjava,AyncTask...等等。可是实际上底层依然是对Handler的封装。那么Handler到底是什么?java
简而言之:面试
Handler就是Android系统提供给咱们,用来更新UI的一套机制,也是一套消息处理机制。经过Handler,能够用来发送消息,处理消息。若是不遵循这样的机制,就没有办法更新UI,会抛出异常。框架
1.Handler: 消息的发送和处理者async
2.Message: 消息ide
3.MessageQueue: 消息存放的队列oop
4.Looper : 从消息队列里面一条一条取消息的消息侦听器,或者消息泵post
5.线程: 当前是在哪一个线程学习
也许不少人在网上都看过不少资料去解释这样一个消息机制,可是若是向别人阐述这样一个原理的时候,或者面试的时候,我相信不少人仍是模棱两可,弄不太清楚。 那么,经过一个简单的生活案例,来帮助理解一下:ui
eg: 咱们都知道读书的时候,咱们常常须要向老师请假之类。this
好比:报告老师,我要上洗手间。而后老师说:容许,快去吧。
过了一会。
又给老师报告:报告老师,后面有同窗踢我凳子。老师说:你先坐前面来,不要理他。
固然,这只是比喻。咱们经过这个比喻,来比较生动形象的去理解handler就容易多了。
1.handler:学生。
2.message:报告老师的内容
3.Looper :老师本身
4.messagequeue: 老师的耳朵和听力记忆
解释:
* 学生(handler)向老师(Looper)举手
* 说 “我要上洗手间”这个报告(message),
* 而后老师的耳朵(messagequeue)听到了这个报告,
* 先是反馈了学生的请求(dispatchHandle),告诉这个同窗,赞成他的请求,
* 因而学生本身就上洗手间去了(handleMessage)
ps: 老师: 在这个过程当中,就是一个消息的接受者,源源不断的接受学生的各类报告或者消息,存在老师的记忆里, 老师又没有分身术,只有一张嘴,因此同一时间,只能根据记忆中的消息,一条一条的反馈给学生,处理他们的请求。 学生: 在这个过程当中,咱们能够发现,学生既是消息的发出者,又是消息的处理者。 收到老师的赞成后,因而就高高兴兴的去上洗手间去了。
整个过程如图:
由图能够看出:
1.handler负责发送消息,接收处理消息
2.Looper负责接收handler发过来的消息
3.MessageQueue就作为Looper消息泵内部的消息容器 3.Looper在内部,将发送过来的消息,交给自身的消息队列,并按时间顺序加入其中 4.Looper在内部,经过不断循环的方式,将消息从队列中一个一个取出,回传给handler
此时你有可能会问:那么Handler它怎么知道应该往哪发消息,而且发给哪一个Looper,加入这个Looper的消息队列呢?答案在构造方法中。
Handler的建立,调用Handler的构造方法便可。 new Handler(). 那么咱们看下Handler的构造方法都作了些什么呢?Handler的构造方法有好几个,咱们先从空构造看起:
//从这开始看起,空构造 public Handler() { this(null, false); } public Handler(Callback callback) { this(callback, false); } public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); } public Handler(boolean async) { this(null, async); } //而后看到这个构造方法 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()); } } //构造方法内部,有一个默认的looper对象,而且这个对象是经过myLooper获得,也就是当前线程的looper。 //当前线程:默认状况就是主线程,为何会是主线程,后面会讲 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; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
上面代码能够看出,在handler的默认构造器中,有一句:mLooper=Looper.myLooper(). 这说明Handler 默认的时候,有一个Looper对象。可是这个Looper对象是怎么建立得来的呢?点击去发现:就是根据当前线程返回一个looper对象。当前线程是什么呢?默认状况下,就是主线程,也就是MainLooper.
/** \* Return the Looper object associated with the current thread. Returns \* null if the calling thread is not associated with a Looper. */ //解释一下:根据当前线程,返回looper对象。若是线程没有与之关联的Looper,那么返回空 public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
好了,看到这里,咱们就看到了Handler和一个默认looper对象如何关联的。至于looper对象的如何建立,后面再详细讲解。
咱们能够得出结论:
* 默认状况下:new Handler()中的looper对象是主线程的looper对象 ,那么消息就是发给主线程的handler进行处理。
* 须要和特定线程的Handler通讯,咱们就须要调用new Handler(Looper looper) ,传入特定线程的Looper对象便可。
* Looper对象是属于什么线程,那么handler,就是往哪一个线程进行发送消息和处理消息。
搞清楚Handler和Looper如何进行关联的关系之后,咱们从消息的发送开始理解。
Handler 如何发送消息,消息从哪里产生? 要搞清楚消息的产生,咱们首先要知道handler发送一条空消息是sendEmptyMessage().那么咱们就跟踪这个方法: 方法的参数what ,就是一个标记位,先无论它。
/** public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }
再继续往下跟踪
//这里能够看到,sendEmptyMessage()默认会调用sendEmptyMessageDelayed()方法 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { //内部,经过Message.obtain(),产生了一条消息Message Message msg = Message.obtain(); msg.what = what; //而后再调用sendMessageDelayed()方法 return sendMessageDelayed(msg, delayMillis); }
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
这里能够看到发送空消息时,Message是在方法内部,经过Message.obtain产生的。 而且会层层调用,最终是这么一个方法路径:
sendEmptyMessage-->sendMessageDelay-->sendMessageAtTime ,最终都是调用sendMessageAtTime()来发送消息的。
经过上面sendMessageAtTime()发送消息,消息产生后,按照前面的图的理解,它是会发送出一个Messgae,而且发给Looper,由Looper加入到消息队列的。那么代码上是怎样的呢?
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { //1.首先获取到queue对象, MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } //2\\. 将消息,插入到这个消息queue队列中去,而且附带了一个时间值 return enqueueMessage(queue, msg, uptimeMillis); }
咱们能够看出:
在最终发送消息的地方,拿到了Queue队列对象,而后就把消息加入到了这个Queue队列中去了。 这个Queue对象的获取,咱们能够观察handler的构造看到:每一次Handler建立的时候,会拿到looper对象,再经过looper对象来获取到内部的这个Queue队列对象。回顾handler的建立可发现,以下:
public Handler(Callback callback, boolean async) { .... .... //1先拿到线程的looper mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //2经过looper获取到消息queue队列 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
再看下消息加入queue队列的过程
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { //这里能够发现 消息msg的target属性:是this,也就是handler 自身当前对象 msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
在加入队列的时候,能够看到消息msg的地址,也就是处理者target(由谁来最终处理消息),赋值为this。
这也就说明了,handler默认状况下,发送消息的是它本身,处理消息的也是它本身。
总结一下上面消息的发送过程:
* 发送出去 sendEmptyMessage(),消息的产生在这个里面
* 调用sendEmptyMessageDelay()
* 内部调用sendMessageDelay()
* 内部调用sendMessageAtTime()
* 内部经过当前线程,首先获取到mQueue对象,也就是 消息队列对象MessageQueue
* 当queue不为空的状况下,设置 target,发送给谁, 默认是this --handler本身
* 而后把消息message,放到消息队列中。queue.enqueueMessage(消息,时间);
####7. 侦听消息和取消息的过程
咱们知道,消息发送到Looper中后,就进入到了队列中,而后等待Looper的循环取出进行分发。那么Looper.loop() 这个循环的过程是在何时触发的呢?因为Android默认的线程是主线程,因此在应用进程启动以后,就会进入ActivityThread这个主线程中,而在这个ActivityThread中的main()方法,就会触发Looper.loop()开始侦听主线程的消息。
//main方法
public static void main(String[] args) {
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//1. 触发loop
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
能够看到,在主线程的ActivityThread main()方法内部,触发Looper.loop()。学过java的人都知道,main方法是一个类的主入口.
那么loop是如何进行取消息的呢?点进去继续往下看
public static void loop() { // 1.拿到当前线程looper对象 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } 2\. 获得 looper对象内部的消息队列queue final MessageQueue queue = me.mQueue; ... ... //3.死循环,配合队列进行取消息 for (;;) { //4.取出一条消息 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 slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); final long end; try { //4.分发消息 msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } } }
能够看到:
Looper.loop()方法中
2.经过myLooper,拿到一个Looper对象
3.取出looper中的消息队列 mQueue
4.而后经过一个死循环,里面经过mQueue.next来取消息
若是消息为空了,就return掉,
5.若是消息不为空, 就会调用
msg.target.dispatchMessage(消息)。将消息发出去
msg.target:就是handler本身
handler.dispatchMessage(消息)方法,将消息回调到dispatch中去
经过上面Looper取消息的过程。咱们看到了。消息在最终取出后,会经过 dispatchMsg进行回传,交给处理者。 这个处理者,被赋值在Msg.target中. Msg的target本质上就是handler。
在前面发送消息,将消息加入队列的时候,咱们看到过,msg.target=this,是在那个时候将消息的处理者进行了赋值。
因此这里,当取出消息后,就又经过handler,经过它的dispatchMessage(msg)进行回传的。
} final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); final long end; try { //消息分发,回传给处理者 。也就是handler本身。 msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } }
继续往下跟踪能够发现:
/** \* Handle system messages here. */ public void dispatchMessage(Message msg) { //若是消息的callback 处理者不为空,就经过这个callback进行处理。这个callback是什么呢? 后续再讲解 if (msg.callback != null) { handleCallback(msg); } else { //默认状况下,走这个分支 if (mCallback != null) { //若是全局的callback不为空,就会执行这里,再也不执行handlemessgae if (mCallback.handleMessage(msg)) { return; } } // 回传给消息处理者,处理消息, handleMessage(msg); } }
分发消息后,默认会进入第二个分支。一般状况下callback是没有进行设置,因此直接就会回调handleMessage(msg).走完整个流程.进入处理消息流程
但是这个msg.callback是什么呢? 还有全局的mCallback又是什么呢? 分发消息的时候,若是这些不为空。又会触发什么呢?继续日后看
因为咱们知道通知UI刷新的机制有4种方式:
view.post(runnable) handler.post(runnable) runOnUiThread(runnable) handler.sendMsg(runnable)
咱们跟踪一下view.post(runnable).进入view源码:
//传入一个runnable public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { //而后将runnable,交给handler的post执行 return attachInfo.mHandler.post(action); } // Postpone the runnable until we know on which thread it needs to run. // Assume that the runnable will be successfully placed after attach. getRunQueue().post(action); return true; }
而后进入到handler的内部中post
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } 复制代码能够看到runnable,被包装进入到了发送消息的getPostMessage(r)方法中。跟进去: private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); //看到没!!! callback,原来就是指 咱们使用view.post(runnbale)的这个对象 //这个runnable,会赋值给msg.callback。 //因此当咱们使用别的方式进行更新UI或者消息通讯的时候,在handleMessage前,就会进入callback不为空的判断 m.callback = r; return m; }
也就是这里msg.callback: 再贴一遍代码
/** \* Handle system messages here. */ public void dispatchMessage(Message msg) { //若是消息的callback 处理者不为空,就经过这个callback进行处理。这里就是使用别的方式进行更新UI或者消息的时候,进入这里处理,再也不进入handleMessage if (msg.callback != null) { handleCallback(msg); } else { //默认状况下,走这个分支 if (mCallback != null) { //若是全局的callback不为空,就会执行这里,再也不执行handlemessgae if (mCallback.handleMessage(msg)) { return; } } // 回传给消息处理者,处理消息, handleMessage(msg); } }
而mCallback 则是咱们初始化构造handler的时候,传入的callback,进行拦截消息处理使用。
咱们能够发现,最终都是进入到了handler的post方法中,经过handler机制来实现。
未完待续....
继续讲解更深刻的细节...
这里发现有一个sThreadLocal对象,咱们的looper对象就是从这个对象中获取的。这个ThreadLocal对象,其实就是一个与线程相关的对象,保存了线程的相关变量,状态等等。再继续往下看:发现最终就是从这个线程相关的对象中,内部有一个map对象,从里面获取得来。这个地方只是一个单纯的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(); }
这个地方依然不是咱们想要的答案,咱们想看的是Looper对象是在哪里建立的。
今年金九银十我花一个月的时间收录整理了一套知识体系,若是有想法深刻的系统化的去学习的,能够点击传送门,我会把我收录整理的资料都送给你们,帮助你们更快的进阶。