Handler是Android系统中重要的组成部分,不管是Android的原生代码中,还是我们在开发应用程序的过程中,都会大量使用Handler,来进行消息的处理。要想更好的使用Handler,就发须理解Android的Handler消息处理机制。详细的Handler消息处理机制,请移步Android应用程序消息处理机制(Looper、Handler)分析
在这里,从如下几个方面去了解Handler。
- Handler的整体架构
- Handler中SendMessage、PostMessage两者的联系及区别
- 如何在一个线程中使用Handler来处理消息
一、Handler的整体架构
在Handler的消息处理机制中,有几个非常重要的类,分别是:Handler、Looper、MessageQueue、Message。
1. Handler: 用于发送和接收并处理消息。
2. Looper: 用于不断的从MessageQueue中取出消息。
3. MessageQueue: 用于装载消息。
4. Message: 消息的实体。
二、Handler中sendMessage、postMessage两者的联系及区别
要弄清楚sendMessage、postMessage这两者的联系及区别,我们就先来看看都有哪些方法吧。
Handler中所有的send方法
Handler中所有的post方法
从Handler的send和post的这些方法中,给我们一个直观的区别是:
send都是很明确的发送一个Message;post并没有看出向外发送Message,而是在post的同时可以处理Runnable。
为了看清楚这两种发送消息的本质,我们就去看看Handler的这几个发送消息的方法源码吧。
先从send的看起,就以sendEmptyMessage来说吧,方法如下:
public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }
在sendEmptyMessage方法中又调用了sendEmptyMessageDelayed(int what, long delayMillis)方法,
在sendEmptyMessageDelayed方法中又调用了sendMessageDelayed(Message msg, long delayMillis)方法,public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }
在sendMessageDelayed方法中又调用了sendMessageAtTime(Message msg, long uptimeMillis)方法,public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
在sendMessageAtTime方法中又调用了enqueueMessage()方法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); }
现在再来看看post的过程,那我们就分别看看post的几个方法都是怎样处理的。
post(Runnable r)
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
postAtFrontOfQueue(Runnable r)
public final boolean postAtFrontOfQueue(Runnable r) { return sendMessageAtFrontOfQueue(getPostMessage(r)); }
postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); }
postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); }
postDelayed(Runnable r, long delayMillis)
public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); }
看了post的几个方法后,我们就很清楚的知道,最后还是调用了send的对应方法。
小结:
区别:sendMessage方法会直接发送Message,而postMessage在发送Message的同时还可以处理线程。
联系:
1. sendMessage和postMessage都可以发送消息。
2. postMessage的方法最后都会调用sendMessage的方法。
三、如何在一个子线程中创建Handler对象
要使用Handler,则必须先创建一个Handler的对象,并重写Handler类中的handleMessage()方法,通常我们在主线程中的创建方法如下:
Handler handler = new Handler() { public void handleMessage(Message msg) { }; };
而如果我们要在一个子线程中,使用上面的这种方式创建Handler对象,如下:
class SubThread implements Runnable { public Handler mHandler; @Override public void run() { mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; } }
按照上面的方式创建Handler,行不行呢?答案是:不行。如果我们在子线程的run()方法中使用上面的创建方式,就会抛出如下异常:
这个异常信息告诉我们:如果没有事先调用Looper.perpare(),就不能在子线程程中创建Handler对象。08-25 19:18:22.564: E/AndroidRuntime(27359): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
从这个异常信息已经很明确的告诉了我们:
方法一: 在子线程中创建Handler对象,就在new Handler()的代码行前面先调用Looper.perpare()方法。
为什么在run()方法中调用了Looper.perpare()方法后,就可以正常创建Handler对象了呢?我们就去看看这个方法都做了哪里操作吧
<span style="font-size:14px;">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)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }</span>
再来看看Looper中都定义了哪些成员变量呢?
看了这些后,就应该明白为什么在子线程中一定要在创建Handler对象的前面显示调用Looper.prepare()的原因了吧。就是为了创建一个Looper,并与前面的线程进行关联起来,这样才可以进行消息的处理。<span style="font-size:14px;">// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread;</span>
除了显示调用Looper.prepare(),还有没有其他的方法可以在子线程中创建Handler对象呢?我们就先来看看Handler类的构造方法都有哪些呢?
从Handler的几个构造方法中,我们可以使用Handler(Looper looper)来创建Handler对象,那问题是,这里所使用的Looper是从哪里来的呢?这个Looper对象实例又是在哪个地方和线程关联上了呢?HandlerThread就是用来解决这两个问题的,我们就来看看HandlerThread的源代码吧。
从HandlerThread的源码,我们知道:<span style="font-size:14px;">** * Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called. */ public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } /** * Quits the handler thread's looper. * <p> * Causes the handler thread's looper to terminate without processing any * more messages in the message queue. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p><p class="note"> * Using this method may be unsafe because some messages may not be delivered * before the looper terminates. Consider using {@link #quitSafely} instead to ensure * that all pending work is completed in an orderly manner. * </p> * * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. * * @see #quitSafely */ public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } /** * Quits the handler thread's looper safely. * <p> * Causes the handler thread's looper to terminate as soon as all remaining messages * in the message queue that are already due to be delivered have been handled. * Pending delayed messages with due times in the future will not be delivered. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p><p> * If the thread has not been started or has finished (that is if * {@link #getLooper} returns null), then false is returned. * Otherwise the looper is asked to quit and true is returned. * </p> * * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. */ public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; } }</span>
1. HandlerThread本身就是一个线程。
2.在HandlerThread的run()方法中调用了Looper.prepare()方法,并把Looper实例赋值给了HandlerThread中的成员变量mLooper。
3.调用HandlerThread的getLooper()方法就可以获取到了已初始成功的Looper对象实例。
从上面的这些分析,我们就可以知道了在子线程中创建Handler对象实例的另一种方法。
方法二:启动HandlerThread线程,调用HandlerThread.getLooper(),再调用Handler(Looper) 构造方法。
使用Handler(Looper)创建Handler的示例代码如下:
<span style="font-size:14px;">class SubThread2 implements Runnable { public Handler mHandler; @Override public void run() { HandlerThread t = new HandlerThread(""); t.start(); final Looper looper = t.getLooper(); mHandler = new Handler(looper) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; } }</span>