从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

高斋晓开卷,独共圣人语。这篇文章主要讲述从Handler+Message+Looper源代码带你分析Android系统的消息处理机制相关的知识,希望能为你提供帮助。
PS一句:不得不说CSDN同步做的非常烂。还得我花了近1个小时恢复这篇博客。

引言【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】
作为android开发人员,相信非常多人都使用过Android的Handler类来处理异步任务。
那么Handler类是怎么构成一个异步任务处理机制的呢?这篇
博客带你从源代码分析Android的消息循环处理机制。便于深入的理解。

这里不得不从“一个Bug引发的思考”開始研究Android的消息循环处理机制。
说来话长。在某一次的项目中,原本打算开启一个工作线程
WorkThread去运行一个耗时任务,然后在工作线程WorkThread中new一个Handler对象来发送消息。代码简化成例如以下:

private class WorkThread extends Thread { private Handler mHandler; @Override public void run() {mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0: Log.e(TAG, 任务运行完毕); break; } } }; //模拟一个耗时任务 try { sleep(9000); } catch (InterruptedException e) { e.printStackTrace(); }//任务运行完毕之后发送一个消息 int what = 0; mHandler.sendEmptyMessage(what); } }

当以上代码运行之后。非常不幸的出现了例如以下的一个Bug:
从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

文章图片

Log打印日志提示:不能在线程中没有调用 Looper.prepare()方法之前就去创建handler对象,言外之意就是,在线程中还没调Looper.prepare()
方法之前。你是不能去创建Handler对象的,否则抛出错误异常。为什么会这样呢?带着疑问。我们跟踪代码进入到Handler源代码中的构造方法:
public Handler(Callback callback, boolean async) { .............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; }

代码第5-8行:我们发现当成员变量mLooper为空值时,就会抛出上面的异常了。意思就是刚才在WorkThread中创建Handler的时候mLooper是
空的,难道不能够这样创建Handler消息处理机制?那为什么在UI线程中直接new一个Hanlder对象不会出错呢?带着这样的好奇心,我们今天来分
析一下Android系统消息处理机制有关的 Handler。Message,Looper,Thread类之间的关联。
  • Handler:消息的运行者,也能够称之为异步任务的运行者
  • Message:消息的封装者。把异步任务,消息码Handler对象等封装成Message对象
  • MessageQueue:消息队列,用于保存当前线程的全部消息Message对象的一个列表
  • Looper:循环者,能让工作线程变成循环线程,然后从消息队列中循环读取消息
  • Thread:异步任务或者耗时任务运行场所,一般开启一个新的工作线程处理耗时任务
消息的运行者–Handler在Android的消息处理机制中,Handler扮演者重要的角色。Handler负责例如以下几个工作:
消息的发送 消息的入列 消息的调度/消息的分发 消息的处理
1-1消息的发送对于消息的发送,相信非常多人平时用的最多的是Handler.sendEmptyMessage()。那么利用Handler发送的消息终于会发送到哪里呢?骚年不用YY了。源代码会告诉你答案,我们跟踪Handler类中的sendEmptyMessage方法:
/** * Sends a Message containing only the what value. * * @return Returns true if the message was successfully placed in to the *message queue.Returns false on failure, usually because the *looper processing the message queue is exiting. */ public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }/** * Sends a Message containing only the what value, to be delivered * after the specified amount of time elapses. * @see #sendMessageDelayed(android.os.Message, long) * * @return Returns true if the message was successfully placed in to the *message queue.Returns false on failure, usually because the *looper processing the message queue is exiting. */ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 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); }

有以上代码发现。Handler消息的发送终于都会调用sendMessageAtTime成员方法。该方法首先推断当前Handler的成员变量mQueue是否为空,假设为空。则打印一个警告。而且返回false。表
示该消息发送失败。那么成员变量mQueue是神马东西呢?mQueue是MessageQueue对象,而MessageQueue类是一个消息队列。被Looper
对象持有。
关于MessageQueue消息队列相关内容后面会展开分析。继续分析代码,假设消息队列不为空,则会调用enqueueMessage方法。跟踪代码进入该方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }

首先。将当前类Handler对象赋值给消息Message类中的target成员变量。然后调用消息队列MessageQueue类中的enqueueMessage方法将
该消息msg插入到消息队列中。
这个过程称之为消息入列的一个过程。

1-2消息的入列有1-1节可知,消息的入列是调用MessageQueue消息队列类中的enqueueMessage成员方法实现的,跟踪代码看看消息入列的详细实现
boolean enqueueMessage(Message msg, long when) { //推断消息的目标对象是否为空 if (msg.target == null) { throw new IllegalArgumentException(Message must have a target.); } //推断消息是否正在使用 if (msg.isInUse()) { throw new IllegalStateException(msg +This message is already in use.); }synchronized (this) { //推断是否正在清除消息队列 if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target +sending message to a Handler on a dead thread); Log.w(MessageQueue, e.getMessage(), e); msg.recycle(); return false; } //标记消息正在使用 msg.markInUse(); //对消息的延时处理时间幅值 msg.when = when; //保存消息队列中的延时时间最小的那个消息 Message p = mMessages; boolean needWake; //条件推断。消息入列,将延时时间最小的那个消息赋值给mEssages变量 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 { // Inserted within the middle of the queue.Usually we don‘t have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked & & p.target == null & & msg.isAsynchronous(); 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; }

分析:
1.代码第3行:推断当前入列的消息的目标处理对象是否为空。有1-1节我们知道msg.target的值是一个Handler实例。
换言之,假设消息的目标处
理对象Handler为null。那么该消息就没有Handler去处理它。因此此处抛出一个异常
2.代码第7行:推断当前Message是否正在使用?假设是则抛出异常。说明一个同样的消息不可能同一时候存在同一个MessageQueue消息队列中。
3.代码第13行:推断当前消息队列是否正在退出?假设正在退出,则抛出异常。说明当前Message消息无法入列。由于MessageQueue消息队列退出了。

4.代码第27-52行:Message消息依照延时时间大小插入当前MessageQueue消息队列中,终于延时时间最短的消息在队列的最前面。
总结:到此。我们知道Handler将消息发送到消息队列MessageQueue中去了。那么这个消息队列MessageQueue是从哪里来
的呢?它属于谁呢?这里直接给出答案。MessageQueue消息队列是在Looper类中创建,Looper循环则持有当前线程中的消息队列
MessageQueue。至于为什么是这样。后面给出详解。
1-3消息的调度/消息的分发有1-2小节我们知道,消息的运行者Handler将消息Message发送到消息队列MessageQueue中。而且消息队列中的全部消息都是依照时间排列。
那么在消息队列MessageQueue中的消息又是怎么分发出去的,或者说消息队列中的消息是怎么被消费掉的?如今我们来解答1-2小节中的最后一个问题。消息队列MessageQueue从哪里来?属于谁?在文章的一开头。
我们有“一个Bug引发的思考”知道了在线程中创建Handler对象之前须要调用Looper.prepare()。否则会抛出异常。那么我们就来分析一下Looper这个类:
/** * Class used to run a message loop for a thread.Threads by default do * not have a message loop associated with them; to create one, call * {@link #prepare} in the thread that is to run the loop, and then * {@link #loop} to have it process messages until the loop is stopped. * * < /code> Most interaction with a message loop is through the * {@link Handler} class. * *This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * **class LooperThread extends Thread { *public Handler mHandler; * *public void run() { *Looper.prepare(); * *mHandler = new Handler() { *public void handleMessage(Message msg) { *// process incoming messages here *} *}; * *Looper.loop(); *} *} */

分析:源代码开头给出了一个非常长的说明。大意是:Looper类作用是为一个线程构造消息循环的,由于线程Thread默认是不带消息循环的。因此
你能够调用Looper类中的prepare方法去为构造一个带消息循环的线程,而且调用Looper.loop()方法启动循环去循环处理消息。直到loop循环结
束。
而且Google官方还提供了一个标准的构造一个带消息循环的线程实例,代码例如以下:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }

以上代码就是创建带消息循环的线程标准写法。那么我们来看看Looper.prepare()方法做了什么:
public final class Looper { private static final String TAG = Looper; // 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.classfinal MessageQueue mQueue; final Thread mThread; private Printer mLogging; /** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ 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)); } }

分析:
1.代码第24行:调用sThreadLocal.get()获得存储在本地线程中的Looper值。假设本地线程ThreadLocal中有当前的Looper对象,者会抛出一个异
常:”Only one Looper may be created per thread”每个线程仅仅能有一个Looper对象。
所以每个线程仅仅能拥有一个Looper对象。关于ThreadLocal类,这里不展开学习,主要作用是将Looper对象存储在本地线程ThreadLocal中。
2.代码第27行:将当前的Looper对象保存在本地线程对象ThreadLocal中。
至此。Looper的准备工作就完毕了。
Looper的准备工作完毕之后,我们来看看Looper的启动方法Looper.loop(),进入loop()方法代码例如以下:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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; // 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.recycleUnchecked(); } }

分析:凝视开头就描写叙述了。该方法的作用是为了在线程中构建一个消息循环机制,当然你能够调用Looper类中的quit()成员方法结束当前loop循环。
代码第10行:获得当前线程Thread的消息队列而且赋值给本地变量queue。
代码第17-49行:构建一个死循环来遍历当前Looper中的消息队列。

代码第18-22行:每次遍历都获取消息队列中最前端的消息,也就是延时时间最短的消息。
当从消息队列中获取的消息为空,则说明该消息队列已经退出。

代码第31行:这一行是重点。此处调用了当前消息的目标对象去分发消息。有1-1小节的最后一段我们知道,消息队列的目标对象就是Handler对象。因此这里就是调用Handler去调度消息或者叫分发消息。有此处也看出来,Message消息是有哪个Handler发送的,就有哪个Handler去分发消息。

跟踪代码进入
msg.target.dispatchMessage(msg);

以上方法在Handler类中
/** * 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); } }

该方法就是处理系统消息的地方,以上代码有三个分支。我们先看最后一个分支,就是运行handleMessage(msg); 方法。跟踪代码:
/** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }

我擦,这么简单,就一个空方法?那怎么处理消息呢?凝视已经告诉我们了,Handler的子类必须重写该方法用来接收消息。也就是说最后的消息
处理逻辑是延伸给Handler类的之类了。相信读者对该方法应该不陌生吧。就是我们常常在实现Handler类中重写的那个方法,消息的处理就在这种方法里面实现了。

到此,消息的调用/消息的分发就结束了,最后通过一个空方法将消息的处理逻辑留给了Handler的之类。
1-4消息的处理消息有以上三步操作,最后进入消息的处理阶段。这里就到了我们非常熟悉的地方了,消息的处理是留给我们Handler子类去实现的,也就是我们平时编写Handler消息那样:
public Handler mHandler; mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } };

Handler消息运行过程总结:以下用一张图来描写叙述消息的发送,消息的入列,消息的分发。消息的处理四个过程。

从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

文章图片

有线程中的Handler把Message类封装的消息发送到当前线程的Looper对象中的消息队列MessageQueue中,然后Looper遍历循环消息队列MessageQueue,从消息队列中取出消息。通过target Handler将消息分发出去,最后当前线程中的Handler获取到该消息,并对消息进行处理。

Handler有关的构造方法分析Handler类源代码发现,Handller类有非常多个构造方法。爱思考的你肯定会问,这些构造方法有什么不同呢?那么我们就从代码中来分析他们之间的不同吧:
2-1 不带參的构造方法
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //接收消息之后,处理消息 } };

我们一般在UI线程中这么来实例化一个Handler对象。然后通过重写Handler类中的handleMessage(Message msg)方法来处理消息。
2-2带一个參数Callback的构造方法
private Handler handler1 = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { //接收消息之后。处理消息 return true; } });

此处的Callback參数是Handler类的内部回调接口,我们通过实现Callback接口中的handleMessage(Message msg)方法来处理消息。

2-3带两个參数的构造方法
private Handler handler2 = new Handler(Looper.myLooper(), new Handler.Callback() { @Override public boolean handleMessage(Message msg) { //TODO 接收消息之后,处理消息 return true; } });

第一个參数是当前线程的Looper对象,第二个參数是Callback接口。消息的处理和2-2小节一样。唯一不同的地方就是多了一个Looper參数。
总结由1-3小节我们发现。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); } }

1.而当你使用2-1小节的构造方法创建Handler对象时。就是採用上面代码中的第三种处理消息的方式了,即重写Handler类中的handleMessage(msg)方法。
2.当你使用2-2和2-3小节的构造方法创建Handler对象时。就採用上面代码中的第二中处理消息的方式,即实现Handler类中的Callback接口中的
handleMessage(msg)方法。
值得注意的是。假设Callback接口回调处理消息返回值是false的话,此消息还会调用第三种处理消息方式,因此没有特殊需求,我们一般在实现Callback接口回调方法时都返回true。
3.那么上面代码第一种处理消息的方式handleCallback(msg)是什么时候触发的呢?上面代码加了一个if条件推断,仅仅有当msg消息中的成员变量
callback不为空时才调用该方式处理消息。
那什么时候callback不为空呢?带着这个问题继续分析Handler发送消息的方法。
Handler发送消息的方法handler发送消息的方法有多达11种,一听吓一跳。这么多方法怎么区分?不用怕。我把这些方法分为例如以下两类。
  • send系列
  • post系列
3-1 send系列
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //接收消息之后。处理消息 } }; Message msg = mHandler.obtainMessage(); //发送一个消息码为0的空消息 mHandler.sendEmptyMessage(0); //发送一个消息码为0,绝对时间点为1000ms的空消息,该时间应该大于等于当前时间。下同 mHandler.sendEmptyMessageAtTime(0, 1000); //发送一个消息码为0,延时时间为1000ms的空消息 mHandler.sendEmptyMessageDelayed(0, 1000); //发送一个没有延时的msg封装的消息 mHandler.sendMessage(msg); //发送一个绝对时间点为1000ms的msg封装的消息 mHandler.sendMessageAtTime(msg, 1000); //发送一个延时时间为1000ms的msg封装的消息 mHandler.sendMessageDelayed(msg, 1000); //立即发送一个msg封装的消息到消息队列的最前端 mHandler.sendMessageAtFrontOfQueue(msg);

分析源代码你会发现。除了最后一个方法。以上全部的方法最后都会调用例如以下方法:
/** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) < var> uptimeMillis< /var> . * < b> The time-base is {@link android.os.SystemClock#uptimeMillis}.< /b> * Time spent in deep sleep will add an additional delay to execution. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be *delivered, using the *{@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was successfully placed in to the *message queue.Returns false on failure, usually because the *looper processing the message queue is exiting.Note that a *result of true does not mean the message will be processed -- if *the looper is quit before the delivery time of the message *occurs then the message will be dropped. */ 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); }

分析:以上凝视都解释的非常清楚。第一个參数就是Message类封装的消息。第二个參数就是消息的更新时间。该时间是绝对时间。

3-2 post系列
mHandler = new Handler(); mHandler.post(new Runnable() { @Override public void run() { //TODO 接收消息之后。处理消息 } }); mHandler.postAtTime(new Runnable() { @Override public void run() { //TODO 接收消息之后,处理消息 } }, new Object(), 1000); mHandler.postDelayed(new Runnable() { @Override public void run() { //TODO 接收消息之后,处理消息 } }, 1000); mHandler.postAtFrontOfQueue(new Runnable() { @Override public void run() { //TODO 接收消息之后,处理消息 } });

分析:和send系列大有不同,此处我们的Handler无需在去重写handlerMessage方法来处理消息了,此处将接口类Runnable作为消息发送,然后实现Runnable接口类中的run方法来处理消息。对于这一点我相信非常多刚開始学习的人会有疑问,这里又没有Message封装消息,怎么将Runnable接口类当作消息发送呢? 一句话。还是跟踪源代码看看:
/** * Causes the Runnable r to be added to the message queue, to be run * at a specific time given by < var> uptimeMillis< /var> . * < b> The time-base is {@link android.os.SystemClock#uptimeMillis}.< /b> * Time spent in deep sleep will add an additional delay to execution. * The runnable will be run on the thread to which this handler is attached. * * @param r The Runnable that will be executed. * @param uptimeMillis The absolute time at which the callback should run, *using the {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the Runnable was successfully placed in to the *message queue.Returns false on failure, usually because the *looper processing the message queue is exiting.Note that a *result of true does not mean the Runnable will be processed -- if *the looper is quit before the delivery time of the message *occurs then the message will be dropped. * * @see android.os.SystemClock#uptimeMillis */ public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); }

分析:无论post系列调用哪个方法。终于都会调用上面这种方法来发送消息,你会惊奇的发现,原来post系列也是调用send系列的方法发送方法的。仅仅只是此处调用了getPostMessage方法将Runnable对象转换成Message对象而已。
跟踪代码进入getPostMessage方法:
private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; }

看到没?调用此方法,将Runnable对象r赋值给了Message类中的clalback成员变量。如今我们回想一下2-3小节Handler类中的
dispatchMessage方法处理消息的三种方式,此处将Runnable接口对象赋值之后Message类中的msg.callback就不会为空,因此调用第一种处理消息的方式。
第3节总结:无论3-1或者3-2小节调用那种方式发送消息,终于都会调用Handler类中的enqueueMessage成员方法,将消息依照消息更新时间顺序插入到消息队列中。这个过程的分析能够參考1-1小节最后一段内容。

在Message消息封装者类中有这么一段凝视:
/*While the constructor of Message is public, the best way to get * one of these is to call {@link #obtain Message.obtain()} or one of the * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull * them from a pool of recycled objects */

这段话告诉我们。当你须要构造一个Message消息对象的时候,最好的方法是调用Message.obtain()或者Handler.obtainMessage()方法来获得,而不是这样获得:
Message msg1 = new Message();

为什么这样获得Message对象不好?我们跟踪源代码瞧瞧不就知道了。

/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ 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(); }

这是一个Message类中的静态方法,方法开头解释的非常清楚:从全局的消息池中获得一个新的消息演示样例,避免用户多次创建Message消息实例浪费
内存。仅仅有当全局的消息池中没有可用的消息实例,才去调用new 一个新的Message消息实例。
总之,归纳成一句话,调用Message.obtain()或
者Handler.obtainMessage()方法避免多次创建Message实例。这样性能更加优化。
Handler移除消息的方法以及Handler内存泄漏问题方法包含例如以下:
//从消息队列中移出post系列方法中Runnable对象的消息 mHandler.removeCallbacks(Runnable r); //从消息队列中移除消息码为“what”的消息 mHandler.removeMessages(int what); //从消息队列中移除全部post系列方法和send系列方法发送的消息 mHandler.removeCallbacksAndMessages(Object token);

可能非常刚開始学习的人会有疑问,开发中非常少用到以上这些方法。那假设你非常少使用以上方法。说明你还是一个Android小白。假设不调用以上对应的方法
去移除消息,就会存在Handler对象内存泄漏的隐患。此话怎讲?我在一次项目开发中遇到这样的问题:
我开启一个新的工作线程WorkThread去运行一段耗时网络请求。当请求结束之后我调用UI线程中的Handler发送一个Message消息给UI线程。但
是此时。我早已经退出当前持有Handler对象的Activity。这会持有Handler的Activity是接收不到WorkThread发送过来的消息的,由于
Activity已经退出。因此会出现一个bug:Handler对象内存泄露。那怎么解决这个Handler内存泄露隐患呢?
4-1非常easy,在持有Handler对象的Activity的onDestory方法调用例如以下代码去移除消息队列中的全部消息
mHandler.removeCallbacksAndMessages(null);

此方法仅仅要传递一个null空參数就表示移出当前线程中消息队列中全部的消息。有些人可能会说,我并不想清除消息队列。可能还有其它Activity等待接收消息,好办。你能够调用例如以下对应的方法移除消息队列中对应的消息:
//从消息队列中移出post系列方法中Runnable对象的消息 mHandler.removeCallbacks(Runnable r); //从消息队列中移除消息码为“what”的消息 mHandler.removeMessages(int what);

4-2那么我们是否还有其它办法解决Handler内存泄漏问题呢?答案是肯定的:将Handler申明为静态的。由于静态类不持有外部类的引用。
public class SubActivity extends Activity { static class StaticHandler extends Handler { WeakReference mActivityReference; StaticHandler(Activity activity) { mActivityReference= new WeakReference(activity); }@Override public void handleMessage(Message msg) { final SubActivity activity = (SubActivity) mActivityReference.get(); if (activity != null) { activity.textView.setText(測试静态Handler解决内存泄漏问题); } } } }

UI线程在使用Handler之前不须要Looper.prepare的原因文章一开头由“一个Bug引发的思考”我们知道。在线程中使用Handler之前须要调用Looper.prepare方法。
爱思考的你会非常纳闷,那为什么我
们的UI线程在创建Handler对象的时候没有调用Looper.prepare方法呢?此时我们不得不从UI线程是怎么来的说起了。只是这里不展开讨论,直接给出答案,我们创建一个Application的时候,都是由系统的一个ActivityThread类来启动的。跟踪代码进入ActivityThread类:
public final class ActivityThread { ...................public static void main(String[] args) { .............. Looper.prepareMainLooper(); .............. } }

该类中有一个main方法,是不是感觉非常熟悉啊?对了,这里就是我们整个Application应用的入口了。在main方法中调用了Looper.prepareMainLooper(),推測该方法里面就调用了Looper.prepare方法来为线程循环loop准备。跟踪源代码:
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException(The main Looper has already been prepared.); } sMainLooper = myLooper(); } }

果然,里面调用了prepare方法。
到此,我们就知道事实上在UI线程中系统在ActivityThread类中就帮我们调用了Looper.prepare方法为UI线程loop循环做准备。
HandlerThread帮你创建循环消息处理机制你可能会遇到这样一种情况,在UI线程中创建一个工作线程WorkThread运行耗时任务。在正常情况下,这个WorkThread运行完任务之后就销毁
了。可是你过了一段时间又有一个耗时任务须要运行。这会你会怎么办?你仅仅能又一次去创建一个WorkThread运行耗时任务。可是线程Thread的每
次创建和销毁都是非常耗系统资源的,因此在这样的情况下。我们的HandlerThread就此诞生了。
HandelrThread是继承自Thread实现了,
也就是说HandlerThread是一个线程。仅仅是该线程里面帮你实现了Looper循环机制,从而使得该线程变成带有循环机制的线程。
言外之
意:当该线程运行完一个耗时任务之后不会立即被销毁,除了用户主动调用HandlerThread类中的quit成员方法来退出当前loop循环。关于
HandlerTread是怎么使用的?能够參考我的还有一篇博客:
http://blog.csdn.net/feiduclear_up/article/details/46840523
总结:通过以上文章分析,基本了解了Android系统的消息处理机制是怎么一回事。也知道了怎么使用Handler,以及Handler使用的一些陷阱等。
来总结一下 Handler,Message,Looper。MessageQueue。Thread之间的关联吧。
假设一个线程Thread想要使用Handler类来发送消息,就必须先调用Looper类中的prepare成员方法来做一些准备工作,然后调用Looper类
中的loop方法启动该线程的循环机制。Handler类把封装成Message类的消息发送到Looper类中的消息队列中,然后Looper类中的loop循环方法
中分发消息。最后将对应的消息对象分发到对应的target handler类中去处理消息。
由此我们知道:一个线程Thread中仅仅能拥有一个Looper对象,且一个Looper对象中仅仅能拥有一个MessageQueue消息队列,可是一个Thread
线程中能够有多个Handler对象,而多个Handler对象共享同一个MessageQueue消息队列。最后提供一个Handler消息处理机制的流程图
从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

文章图片

【从Handler+Message+Looper源代码带你分析Android系统的消息处理机制】【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】




    推荐阅读