Handler是为了解决非UI线程中UI更新的问题,这里会产生一个疑问。为啥要在UI线程中更新,通常都知道会产生卡顿问题。html
上张官方关系类图,压压惊:
能够看到他有四个子类,前面两个是与异步数据库操做相关的(contentProvider),后面两个是与网络请求(一个是处理http受权,另外一个是处理SSL错误请求)android
MessageQueue与Message,Looper,Handler数据库
Handler 主要功能是发送消息和处理接受消息。通常经常使用的 handler.sendEmptyMessage(int what)
和 sendMessage(Message msg)
方法,下面就从 sendEmptyMessage(int what)
方法看看它是怎么运做的?缓存
sendEmptyMessage 内部调用关系以下:网络
sendEmptyMessage => sendEmptyMessageDelayed => sendMessageDelayed => enqueueMessageapp
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { //构造新的消息 使用sPool全局池保存回收的消息链表进行空消息缓存 Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } ... 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); }
uptimeMillis
没有被用到,那他是用来干什么的?(uptimeMillis
是开机到如今的毫秒数,内部实现是一个native方法 )msg.setAsynchronous
怎么使用其值?看了obtain方法后发现,sPool默认是static,因此属于Message类,共享的,没有初始化,那它何时进行赋值。答案就在recycle方法,顾名思义其实做用至关于回收那些没用的消息,那这个是怎么工做的?异步
... //recycle内部调用的recycleUnchecked函数 void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; //关键代码,其实能够回收的话至关于把消息放到单链表的表头 synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
能够本身纸上画下,下面看图说话:
ide
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; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
直接上图:
函数
归纳:MessageQueue中使用一个单链表来维护消息队列。经过Looper对象分发消息,可是不能直接把Message入队,须要经过Looper关联的Handler来发送消息。oop
关键看两个方法:enqueueMessage 与 next(后续分析) 方法,前面一个是消息入队,后面一个是消息出队。
先来看看 enqueueMessage
方法,首先它有两个参数:消息--msg 和触发时间--when,简单来讲,若是p为空的话直接赋值 mMessages = msg
,若是p不为空的话则须要根据触发时间--when插入到链表合适的位置。
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) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { ... //关键代码 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); } } return true; }
Looper的构造函数修饰符是private的,那么他是在哪里被实例化?经过搜索,发现 prepare()
和 prepareMainLooper()
两个方法。
prepare()
方法官方说明;
做为looper初始化当前线程。提供一个机会来建立handler并使用looper。在使用以前,请在此方法以后调用loop(),并在结束时调用quit()
prepareMainLooper()
方法官方说明;
做为looper初始化当前线程,并标记其为application主线程的looper。在application主线程中的looper被Android系统建立,所以开发者请永远不要手动调用这个方法。
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } 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)); }
看上面的prepareMainLooper()
代码,发现作了两个事: prepare(false)
和 myLooper()
。
prepare(false)
方法中的sThreadLocal字段的类型是 ThreadLocal
,用来干什么呢?实现一个线程本地存储,一个让每一个线程都有拥有value的变量。另外,能够看看构造函数Looper干了些什么事情?private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
对于myLooper()
来讲,prepare()中提到了会将looper放到线程存储ThreadLocal中,此处只须要从中取出并返回便可,所以代码只有一行return sThreadLocal.get();
疑问
在activity当中实例的Handler,咱们并无调用loop方法?
查看prepareMainLooper()调用者能够看到,在SystemServer.run()与ActivityThread.main()中都在调用Looper.prepareMainLooper()后不远就调用了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; } msg.target.dispatchMessage(msg); msg.recycleUnchecked(); } }
这里就一目了然了:一个死循环,不断从队列中取消息并分发,若是取到null就说明消息队列已经退出或被释放,此时loop终止。msg.target.dispatchMessage(msg)中target即是在发送消息的handler对象,dispatchMessage()即是对消息的处理了。