Handle的原理代码实现
Posted 风也不知道往哪吹
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handle的原理代码实现相关的知识,希望对你有一定的参考价值。
本文从源码的角度来分析Handle如何实现的。
首先我们得知道Handler,Looper,Message Queue三者之间的关系
- Handler封装了消息的发送,也负责接收消。内部会跟Looper关联。
- Looper 消息封装的载,内部包含了MessageQueue,负责从MessageQueue取出消息,然后交给Handler处理
- MessageQueue 就是一个消息队列,负责存储消息,有消息过来就存储起来,Looper会循环的从MessageQueue读取消息。(西安尚学堂)软件开发
源码分析
当我们new一个Handler对象的时候,看看他的构造方法里面做了什么.
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class 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()); } } 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; }
从源码中我们看到他会调用Looper.myLooper方法获取一个Looper对象,然后从Looper对象获取到MessageQueue对象。
Looper myLooper()
跟进去看看Looper.myLooper()方法做了什么。这是一个静态方法,可以类名.方法名直接调用。
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
这个方法里面就一行代码,从sThreadLocal中获取一个Looper对象,sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。底层是ThreadLocalMap,既然是Map类型那肯定得先set一个Looper对象,然后我们才能从sThreadLocal对象里面get一个Looper对象。
ActivityThread main()
ActivityThread类是android APP进程的初始类,它的main函数是这个APP进程的入口。那么这个main函数干了什么事呢。
public static final void main(String[] args) { ------ Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); ----- }
在第二行代码调用Looper.prepareMainLooper()方法,第13行调用了Looper.loop()方法。
Looper prepareMainLooper()
继续跟进Looper.prepareMainLooper()方法,在这个方法中第一行代码调用了内部的prepare方法。prepareMainLooper有点像单例模式中的getInstance方法,只不过getInstance会当时返回一个对象,而prepareMainLooper会新建一个Looper对象,存储在sThreadLocal中。
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
Looper prepare()
继续跟进prepare方法,看第5行代码,新建了一个Looper对象,调用sThreadLocal.set方法把Looper对象保存起来。
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)); }
Looper 构造方法
Looper内部包含了MessageQueue,其实就是在new Looper对象的时候就new了一个MessageQueue对象。
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
Looper loop()
ActivityThread类main方法中调用了Looper的两个方法,前面我们解释了prepareMainLooper(),现在来看第二个方法loop()。
public static void loop() { final Looper me = myLooper();//获取Looper对象 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread."); } final MessageQueue queue = me.mQueue;//从Looper对象获取MessageQueue对象 // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) {//死循环 一直从MessageQueue中遍历消息 Message msg = queue.next(); // might block if (msg == null) { 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.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { //调用handler的dispatchMessage方法,把消息交给handler处理 msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn‘t corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
这个方法的代码比较多。其实就是一个死循环,一直会从MessageQueue中取消息,如果取到了消息就会执行msg.target.dispatchMessage(msg)这行代码,msg.target就是handler,其实就是调用handler的dispatchMessage方法,然后把从MessageQueue中取到的message传入进去。
Handler dispatchMessage()
public void dispatchMessage(Message msg) { //如果callback不为空,说明发送消息的时候是post一个Runnable对象 if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) {//这个是用来拦截消息的 if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//最终调用我们重写的handleMessage方法 } }
这个方法对消息做最后处理,如果是post类型调用handleCallback方法处理,如果是sendMessage发送的消息。看我们有没有拦截消息,如果没有最终调用handleMessage方法处理。
Handler handleCallback()
看到这里我们知道为什么post一个Runnable对象,run方法执行的代码在主线程了吧,因为底层根本就没有开启线程,就只是调用了run方法而已。
private static void handleCallback(Message message) { message.callback.run(); }
前面我们从创建handler对象开始,以及创建Looper,创建MessageQueue的整个流程,现在来分析下,当我们调用post以及sendMessage方法时,怎么把Message添加到MessageQueue?
Handler post()
调用了getPostMessage方法,把Runnable传递进去。
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } Handler getPostMessage()
首先调用Message.obtain()方法,取出一个Message对象,这个方法之前有讲过,然后把Runnable对象赋值了Message对象的callback属性。看到这里我们也明白了dispatchMessage方法为什么要先判断callback是否为空了吧。
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
Handler enqueueMessage()
在post方法里面调用了sendMessageDelayed方法,其实最终调用的是enqueueMessage方法,所以我这里就直接看enqueueMessage方法源码。第一行代码就把handler自己赋值给messgae对象的target属性。然后调用MessageQueue的enqueueMessage方法把当前的Messgae添加进去。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
小结
总结:handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己。MessageQueue就是一个存储消息的容器。
以上是关于Handle的原理代码实现的主要内容,如果未能解决你的问题,请参考以下文章
Handle的原理(LooperHandlerMessage三者关系)
Handle的原理(LooperHandlerMessage三者关系)