Android多线程(二)消息处理机制---Handler、Message、Looper源码原理解析
在Android中UI操作不是线程安全的,只有UI线程才能修改UI,所以我们经常开启子线程去处理一些耗时的操作,然后通过Handler发送消息,在UI线程中接送消息并处理UI组件,一个典型的Handler写法如下:
private Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { ...... } }Runnable runnable = new Runnable(){ public void run() { ...... handler.postDelayed(update_thread, 1000); ...... }};
或者在子线程中创建Handler:
class ChildThread extends Thread { public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { ...... } }; Looper.loop(); } }
为什么在子线程使用Handler需要调用Looper.prepare()和Looper.loop(),而主线程中不需要呢?下面,我们就从源码中解析一下Handler的消息处理机制。
Looper工作原理
我们来看一下Looer的构造函数:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}
在构造函数中创建了一个MessageQueue,正如它的名字,这是一个消息队列,发送的Message都会从消息队列中插入和取出,此外还保存了当前所处的线程mCurrent。注意,Looper的构造函数是private修饰的,也就是说不能通过new来创建一个Looper,只能通过Looper类里面的其他方法来获取,接着看一下prepare()这个方法:
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));}
原来,当我们调用prepare()这个方法的时候,就会为我们创建一个Looper,而且这个Looper很特殊,是存放在sThreadLocal里面的,sThreadLocal是Looper里面一个很重要的成员变量:
static final ThreadLocal sThreadLocal = new ThreadLocal();
Threadlocal保证了我们创建的对象只能被当前的线程访问,即每个线程的Looper都是独有的,而且每个线程只能拥有一个Looer对象,否者就会抛出异常”Only one Looper may be created per thread”。看到这里,也就是解释了为什么在线程中使用Handler时需要调用Looper.prepare(),那为什么在UI线程中不需要调用Looper.prepare()呢,其实在Looper中还有一个方法:
/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); }}
从注释中可知,当我们创建一个应用的时候,系统就已经为创建了一个main looper了,因此当我们使用Handler时就默认使用了这个main looper。Looper.prepare()完成之后接下来就是Looper.loop(),只有调用loop()之后,消息循环系统才真正地运行起来:
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; ...... for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } try { msg.target.dispatchMessage(msg); } finally { ...... } ...... msg.recycleUnchecked(); }}
public static @Nullable Looper myLooper() { return sThreadLocal.get();}
从以上代码看到,loop()方法中通过myLooper()获取了在prepare()中创建的Looper对象,接下来就是一个死循环,只有MessageQueue的next为null即消息为空时才能跳出循环。如果消息不为空,接着就调用msg.target.dispatchMessage(msg)去处理消息,msg.target就是我们创建的Handler对象,消息处理流程在这切换到了Handler中,这样就把Looper、Handler、Message、MessageQueue联系起来了。
Handler工作原理
Handler主要的工作就是发送和接收消息,发送消息是通过一系列的postXXX和sendXXX方法实现的,以上一系列方法最终调用的是sendMessageAtTime()这个方法:
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);}
sendMessageAtTime()负责将Message压如MessageQueue中,然后MessageQueue的next()取出Message交给Handler的dispatchMessage()去处理:
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
如果Message的callback不为空的情况下就通过handleCallback(msg)来处理消息,这里的callback其实是一个Runnable对象,也就是通过post(Runnable r)传入的;如果msg.callback为空,则去检查mCallback是否为空,这个mCallback是Handler内部的一个接口:
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. * * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */public interface Callback { public boolean handleMessage(Message msg);}
如果我们创建Handler的时候使用的是Handler(Callback callback)的话,就需要重写Callback接口的handleMessage(Message msg)方法,这样消息的处理就由Callback处理,如果没有传入自己的Callback,最后就会调用Handler自己的handleMessage(Message msg)来处理消息,这也是我们最常用的方式。
总结
这样,Handler处理消息的流程就分析完了,我们来总结一下:
1、首先我们通过Looper.prepare()创建了一个Looper对象,如果是UI线程的话,系统则会自动为我们通过prepareMainLooper()创建Looper对象,然后在Looper中创建了一个消息队列MessageQueue,每个线程都只对应这个唯一的Looper,每隔Looper又对应着唯一一个MessageQueue;
2、Looper.loop()是一个死循环,不断地从MessageQueue中取出Message交给Handler的 dispatchMessage处理;
3、Handler通过创建Handler时采用的构造函数不一样,采用不同的方法来处理消息。
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- android 深入解析AsyncTask
- Android(安卓)多线程:HandlerThread理解和使用总结
- android自定义dialog弹出框、透明背景
- Android(安卓)多线程:手把手教你使用AsyncTask
- android 跨进程访问service方法
- 发现3 .js与Android和英特尔XDK
- Handler发送消息后消息队列的处理
- 【Android(安卓)Training UI】创建自定义Views(Lesson 2 - 自定