作过windows GUI的同窗应该清楚,通常的GUI操做都是基于消息机制的,应用程序维护一个消息队列,开发人员编写对应事件的回调函数就能实现咱们想要的操做java
其实android系统也和windows GUI同样,也是基于消息机制,今天让咱们经过源码来揭开android消息机制的神秘面纱android
谈起异步消息,就不能不说起Handler,在安卓中,因为主线程中不能作耗时操做,因此耗时操做必须让子线程执行,并且只能在主线程(即UI线程)中执行UI更新操做,经过Handler发送异步消息,咱们就能更新UI,通常的handler的用法以下:windows
public class TestActivity extends Activity { private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); final TextView tv = (TextView) findViewById(R.id.textView); //建立一个handler对象,重写handleMessage回调函数,在回调函数里面作UI更新操做 mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0x1: //在这里更新UI Bundle b = msg.getData(); tv.setText(b.getString("textview")); break; default: break; } } }; new Thread(new InnerRunnable()).start(); } private class InnerRunnable implements Runnable { @Override public void run() { //作耗时操做放在这里 //建立一个消息对象 Message msg = Message.obtain(); msg.what = 0x1; //能够用Bundle传递数据 Bundle b = new Bundle(); b.putString("textview", "异步加载"); mHandler.sendMessage(msg); } } }
咱们简要概括一下Handler的常规使用方法:app
一、在UI线程建立Handler对象,并重写handler的handlerMessage回调函数,能够在回调函数里面作UI更新操做异步
二、子线程完成耗时操做后,建立Message对象,用Message对象保存结果async
三、在子线程经过handler对象调用sendMessage函数发送消息,这样UI线程收到消息后,获取数据,就能够更新UIide
是否是很简单,那如今让咱们一步一步来拨开迷雾,看清android异步消息本质函数
先简要介绍会涉及的组件:oop
Handler:消息发送者ui
Looper:消息循环,负责从MessageQueue获取消息,并处理
Message: 消息,能够存放数据
MessageQueue : 消息队列,负责存/取消息
从上面的例子咱们得知,要使用Handler必需要先在UI线程建立一个Handler对象,那么咱们经过源码查看Handler构造函数,代码位于: com.google.android / android/os/Handler.java,(由于源码较多,因此如下代码截图只包含关键代码)
public class Handler { final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; public Handler() { this(null, false); } 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()); } } 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使用了无参构造函数版本,但内部最终调用了Handler(Callback callback, boolean async)构造函数
在Handler(Callback callback, boolean async)代码开始,先检查FIND_POTENTIAL_LEAKS开关(该开关默认关闭),若该开关打开,则检查Handler所在类是否为匿名类/成员类或局部类时,而且该类是不是static的,若是不是static的,则输出Log提示使用者Handler类不为static可能会致使内存泄露,至于为何会形成内存泄露,这里先卖个关子
调用Looper.myLooper()获取Looper对象,而后经过mQueue = mLooper.mQueue和Looper对象中的消息队列关联
那么跟进Looper.myLooper看看,代码位于: com.google.android / android/os/Looper.java
public final class Looper { static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; 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)); } public static Looper myLooper() { return sThreadLocal.get(); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } }
Looper.myLooper()仅仅是返回一个线程副本,从代码得知,实际建立Looper对象的函数为Looper.paepare(),该函数建立Looper对象后存放到线程本地存储
Looper的构造函数为private,咱们只能经过Looper.myLooper获取Looper对象,而建立Looper对象时,会建立一个消息队列
这样咱们如今明白了handler建立相关的工做,如今让咱们来看看子线程发送消息的处理机制
当子线程发送传递消息时,调用了handler对象的sendMessage函数
public class Handler { final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); } public final boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } 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;能够看到最终sendMessage最终只作了两件事情:
一、经过msg.target = this把Message对象和当前Handler对象关联
二、把消息放到handler中Looper对象的MessageQueue中
消费消息位于Looper.loop函数中
public final class Looper { 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; // 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 (;;) { 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 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); } // 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.recycle(); } } }
Looper.loop函数:
一、经过 final Looper me = myLooper()获取当前线程的Looper对象
二、消息循环中, 经过Message msg = queue.next()获取队列中的消息,若没有消息则阻塞
三、调用msg.target.dispatchMessage(msg)处理消息
四、处理完毕后调用msg.recycle()回收消息
根据上面代码可得知实际处理消息的是msg.target.dispatchMessage(msg),那咱们来看看msg.target究竟是什么东西
public final class Message implements Parcelable { /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next; private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); } public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } }
原来msg.target是一个handler对象,而最终调用的是handler的dispatchMessage函数来处理消息
public class Handler { final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; public interface Callback { public boolean handleMessage(Message msg); } public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } }
根据如下代码能够得知消息处理的步骤以下:
一、先判断Message的callback对象是否为空,不为空则回调Message对象的callback对象的函数(能够再建立Message时指定Callback)
二、若是建立Handler的Callback对象不为空,那么则调用Callback对象的handlerMessage函数
三、若没指定Handler的Callback或者Handler中Callback对象的handlerMessage函数调用失败,则回调handlerMessage,而这个handlerMessage函数正是咱们建立handler时重写的函数
至此咱们明白安卓异步消息的内部机制:
一、子线程经过handler向UI线程Looper中MessageQueue发送message
二、Looper处理消息时再回调handler中定义的回调
至此用一张图总结android异步消息机制(网上找的,凑合看):
因此要让一个线程要想成为消息处理线程,那么必须得有Looper才行,可能此时你会疑惑,为何UI线程没有建立Looper却也能接收Handler发送来的消息?
其实,APP初始化过程当中,android会自动帮UI线程建立Looper对象,代码位于:com.google.android / android/app/ActivityThread.java
public final class ActivityThread { public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } }
能够看到调用了Looper.prepareMainLooper()为主线程建立Looper,最后调用Looper.loop进行消息循环
经过分析源码,能够得知:
一、若是主线程和子线程,或者子线程同子线程通讯,能够调用Looper.prepare()为Looper.loop()为子线程建立消息队列,再经过handler就能够很是简单的实现线程间通讯
二、建立Message对象,必定要用Message.obtain()函数代替new Message()来建立消息,由于Looper处理完消息后,会调用 msg.recycle()函数把Message归还到消息池中,使用Message.obtain会先从消息池中获取,若没有才会建立新的Message,这样能够避免重复建立Message对象
三、Handler所在类必须是static类,由于非static内部类会隐式的持有外部类的引用,假如延时操做还未执行完成时就关闭Activity,由于handler持有Activity的引用,那么Activity就不会被及时回收而形成内存泄露