工作多年,再来从源码的角度一步一步回忆复习Handler的机制


蓦然回首,发现自己已经工作多年,从事android开发已经多年,如今再次和同行谈起Handler的时候,发现互相都只是知道一个大概实现原理和用法,然后互相嗤之以鼻,都说过去也看过源码,了解过原理,可是这么许久过去了,却无法说出更多源码细节,后悔当初看源码的时候,没有好好做个笔记,刚好今天有时间再来翻翻源码,再来复习复习吧,顺便做个笔记吧。


至于用法我就不在赘述了,直接跟源码吧。
至于要用Handler,今天我们还是分几个步骤来说说Handler的原理吧,主要步骤为: 

1.创建Handler及其一些细节

2.使用Handler发送消息及其一些细节

3.处理消息及其一些细节

4.最后总结使用Handler的好处和作用

5.总结使用Handler的时候需要注意的一些细节

6.Handler、Looper、MessageQueue的关系和区别

7.针对Handler 衍生扩展到HandlerThread



一、创建Handler及其一些细节

那么首先就必须的创建一个Handler对象吧,OK,new 一个Handler,直接看构造函数吧。

/**
 * Use the {@link Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
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对象的函数,而在这几个
函数中,又调用了上面这个构造函数,我这样贴是方便大家阅读,这个构造方法也很简单,就是调用了Loop.myLooper()方法获取
一个Looper对象,并赋值给了mLooper,如果mLooper为null,直接抛出异常,这里大家是不是很直接的就看到我们初学者很容易
犯下的一个错误,比如我们在一个新的子线程中,直接创建一个Handler对象的时候,会直接抛出该异常,导致程序崩溃,那么这句
话我么你应该怎么理解呢? 其实就是说不能在一个没有调用Looper.prepare()的子线程中,创建Handler,至于这个异常为什么会抛
出,我们后面再做详细介绍,至于接下来的几行代码,无非就是把构造方法中的参数赋值给了Handler的成员变量mCallback 
和mAsynchronous,然后注意观察一个MessageQueue类型的变量mQueue的赋值,是通过mLooper.mQueue 获取出来赋值给了
mQueue成员变量。

/**
 * Default constructor associates this handler with the {@link Looper} for the
 * current thread.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 */
public Handler() {
    this(null, false);
}


这个default的构造函数应该大家很常用吧,但是我们看,这个构造函数内部就一行代码,又调用了另一个重载的构造函数,
那就是我们最开始贴出来的那个构造函数。OK,这个构造方法,相信大家都经常用吧,同样起方法内部直接调用了最开始贴出的那个构造方法。
/**
 * Constructor associates this handler with the {@link Looper} for the
 * current thread and takes a callback interface in which you can handle
 * messages.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 *
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Callback callback) {
    this(callback, false);
}
这个方法很少用把,需要传递一个Callback对象。

/**
 * Use the provided {@link Looper} instead of the default one.
 *
 * @param looper The looper, must not be null.
 */
public Handler(Looper looper) {
    this(looper, null, false);
}


这个构造方法相信大家很常用吧,这个构造方法需要传递一个Looper对象的构造参数,然后构造方法内部也是一行代码,直接
调用了三个参数的重载构造函数,其实比较关键的一个参数是Looper。
/**
 * Use the provided {@link Looper} instead of the default one and take a callback
 * interface in which to handle messages.  Also set whether the handler
 * should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param looper The looper, must not be null.
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}


 
哈哈,这个三个参数的重载方法,超级简单吧,只不过相比最开始贴出来的那个两个参数的构造方法,多了Looper参数,然而在这个方法
构造方法中,就少了自己去调用Looper.myLooper();去获取Looper对象的步骤,以及获取出来为null的时候的抛出的异常的步,所以IZIMI
这个构造方法就不需要那么麻烦,直接赋值就好了,这里要主要,如果你传进来的Looper为null,loop.mQueue是会直接抛出
空指针异常的,所以使用的时候尽量注意这些问题。
/**
 * Use the provided {@link Looper} instead of the default one and take a callback
 * interface in which to handle messages.
 *
 * @param looper The looper, must not be null.
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}
/**
 * Use the {@link Looper} for the current thread
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
public Handler(boolean async) {
    this(null, async);
}


最后看这两个构造方法把,第一个是调用上面的三个的构造方法,一个是调用最开始贴出来的构造方法,很简单。
 
构造方法都已经介绍完了,都很简单,但是不难看出,在这些构造方法中,必不可少的一个元素那就是Looper和MessageQueue,
不管你用哪一个构造方法创建Handler,都离不开Looper和MessageQueue,是的,这两个是Handler机制得以实现完美功能的
最核心的元素之一。
 
OK,我们针对上面的几个构造参数做个总结:
 
	Looper:    mLooper是Handler的一个成员变量, 如果外部没有通过构造参数传入,那么就调用Looper.myLooper()方法获取一个。
	MessageQueue: mQueue是Handler的一个成员变量,通过mLooper.mQueue直接得到Looper的成员变量,也就是mQueue是
	Looper的一个成员变量,你甚至这样理解更加准确,Looper内部维护着一个MessageQueue,即消息队列。
	
 
 
 

二、使用Handler发送消息及其一些细节

我们还是由浅到深吧,接下来,我们创建好了Handler之后,是不是直接通过Handler对象的sendMessage、sendMessageDelay等系列
方法发送一个任务消息。
我们接下来看看Handler常用的几个发送消息的方法:
很多时候我们喜欢使用sendMessage(Message msg)和sendMessageDelayed(Message msg,long delayMillis)来发送消息,这些消息
发送到哪里去了呢?我们先来看看这两个方法。
/**
 * Pushes a message onto the end of the message queue after all pending messages
 * before the current time. It will be received in {@link #handleMessage},
 * in the thread attached to this handler.
 *  
 * @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 sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}


很简单,调用sendMessage的时候,直接调用了sendMessageDelayed(Message,long delayMillis)方法,因为外界没有
设置一个delay时间,这个方法也不接受一个delay时间的参数,所以在方法内部调用sendMessageDelayed(Message,long delayMillis)
的时候,默认设置的delay时间为0,这是我们暂时这样理解,意思就是说这个消息需要立即执行处理。
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
这个方法也很简单,也是可被外界调用,用来发送任务消息的,其内部也很简单,就是判断,做了一个防呆处理,判断delayMillis是否小于0,如果小于0,将delayMillis重置为0,然后再调用了方法sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);注意这里的第二个参数,SystemClock.uptimeMillis() + delayMillis,SystemClock.uptimeMillis()得到的时间是从开机到当前(现在)的时间毫秒值,为什么要用SystemClock.uptimeMillis()?为什么不用SystemClock.elapsedRealtime();和System.currentTimeMillis();呢?这里又需要做一下小小说明:SystemClock.uptimeMillis(): 刚说了,这个是用来获取从开机到当前(现在)的时间毫秒值,不包括深度休眠的时间,所以用这个来处理时间间隔的任务比较合适。SystemClock.elapsedRealtime(): 这个获取的是从开机到当前(现在)的时间毫秒值,但是他包括深度休眠的时间,所以这个用来处理时间间隔任务的话,是不合适的。System.currentTimeMillis(): 这个就更加不合适,因为这个获取的是系统时间,是从1970.1.1 UTC时间到现在的时间毫秒值,按理来说这个应该也可以啊,但是关键的一个问题就是,系统时间是可以修改的,一旦修改,逻辑实现就错误了。所以System.currentTimeMillis()不适合计算时间间隔,eg,now = System.currentTimeMillis()//do something...duration = System.currentTimeMillis() -now;如果在do something的时候,改变了系统时间,那么 获取duration就不准了。所以这里最后使用SystemClock.uptimeMillis() + delayMillis,如果delayMillis>0的话,那么这个消息,将会在现在之后的未来时间执行处理这个消息,OK,接下里我们来看看sendMessageAtTime这个方法。
 
/**
 * 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);
}
看到了吧,主角又出来了,MessageQueue,这个应该清楚了吧,这个在构造方法里面就会赋值的mQueue,如果mQueue
为空的话,直接抛出异常了,程序直接挂掉。


Ok,如果mQueue不为空的话,然后调用了enqueueMessage(queue, msg, uptimeMillis)方法,注意这里把queue也传递
进这个方法里了,我们看看这个方法。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
OK,看第一行代码,调用了Msg.target = this;   msg不就是一个Message对象,居然把this对象赋值给了msg.target对象,
this不就是咱们的Handler类型的对象,那不就是说Message内部维护着一个Handler类型的成员变量,而且成员变量名为target。
OK,果然没错,Message中确实维护着一个命名为target,类型为Handler的成员变量,OK,第一行代码就是把当前的Handler赋值
给了Message的target成员变量了,最后调用了queue.enqueueMessage(msg, uptimeMillis);注意,这里调用的是MessageQueue的
enqueueMessage(msg, uptimeMillis);方法,我们来直接看看MessageQueue的这个方法。

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(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        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 {
            // 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;
}


首先这个方法一开始就做如下判断: 

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.");
}


很明显,如果target为null直接抛出异常,也就是target不能为null,其实说到这里,有个很明显的比喻可以拿出来说说。
Message 我们因为都可以翻译为"信息","信件",是的,那我就把他看作是一封信件 ,一条消息,那么既然这样,那一封信件
,一条信息,就必须具备一个属性,那就是目的地、目标,这个消息最终到达哪里,target字面意思就有目标的意思,只不过
用在Handler机制中,发送消息,和接受消息的都是Handler而已,暂时我们这样理解吧。
接下来就是判断,如果当前Message正在使用或者正在处理,那么就会抛出状态异常。
上面两个判断很简单。
那么看接下来的逻辑,主要干嘛呢?
主要就是按照delayMillis时间的先后,把Message存入MessageQueue中,这个存储方式其实就是一个链表形式。
用过Handler系统的同学都知道,Handler发送消息,轮询取出消息消息,都是按照delayMillis大小来处理的(一般外界不设置DelayMillis的前提下默认都会设置为0),
但是如果用户设置了delayMiiils的话,比如,用户设置了delayMillis 0,200,500,1000,2000,3000....不等的毫秒值,
所以这里他要处理的逻辑就是,按照delayMillis时间大小来和mQueue中的Message的when时间进行比较,把当前新Message
安插在消息队列的一个合适位置(这里就不多提Message为null的情况),如果有人问你,Looper 轮询MessageQueue中的消息是不是
按照先进先出的方式的时候,你可以大胆的告诉他,不是的,那么接下来说说他们是怎么存的。


先把当前Message标记为正在使用,把一开始的时间毫秒值都赋值给了当前我们send的Message。
然后把当前的mMessage拿出来,赋值给了临时变量p,然后接下来的逻辑就是和当前的Mesaage比较
,如果目前这个新Message的when<0、when=0或者当前Message为null的话,就把这个当前的Message安插在
新的Message后面,另外一个else语句里面处理逻辑就是,和当前mMessage之后的每个节点使用for循环的方式挨个判断和比较
,如果遍历到最后没有节点的话,即p.next()为空的时候,把新的Message挂到p这个节点之后,或者p.next()不为空,那就比较
when的值,如果新Message的when比p.next的值更早,那就把p.next()插在新Message的后面,把新Message插在prev后面,就这样一直
遍历,直到满足p.next 为null或者p.when小于新Message的when。
OK,其实还有两个发送消息的方法我也经常使用,那就是如下两个方法:
/**
 * 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);
}


那看到这两个方法都一样吧,最后还是调用sendMessageDelayed(msg, delayMillis);方法,接下里的步骤都是一样的,只不过上面两个
方法使用更加简单,不需要通过Message传递更为复杂的数据,只需要一个what标记就行,但是在内部,还是自动会创建一个Message的。
所以这样说来,我们说的发送消息,很简单的可以概括为将消息发送到了Looper的MessageQueue中去了。


三、处理消息和细节

上面我知道,消息是发出去了,存在MessageQueue中了,那消息又是怎么分发给了对应的Handler来处理的呢?? 还记的我们最开是说的Looper吗?在接下来的消息分发,Looper扮演十分重要的角色,那他具体做了什么呢? 大家知道,mLooper是哪里来的?通过上面的构造方法我们知道,如果外界不设置传递一个Looper的话,那么默认会 调用Looper.myLooper()来获取一个Looper对象来赋值给mLooper,另一种方式就是外借传递进来赋值给mLooper,那么我们来 ,我们来看看Looper这个类。 通过上面可以看到,Looper这个类是不可以在有子类了,也就是说,不能在继承Looper这个类了,既然Handler需要有一个mLooper, 那我们是不是可以直接随意就创建new一个Looper呢?我们看看他的构造方法。 结果我们发现,找了半天,Looper只有一个构造方法,而且还是私有的,private的,不能直接new出来一个Looper,那我们就 联想到一开始创建Handler的时候,使用了Looper的静态方法myLooper()方法获取了一个Looper对象,我们之间来懒看这个静态方法。
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}


看到这里,发现这个方法超级简单,就一行代码,通过sThreadLocal.get()就能获取一个Looper对象,好神奇一样。我们直接来看看sThreadLocal这个变量,到底是啥玩意?
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
至于ThreadLocal我想通过之后的另外一篇博客来讲解这个类,今天主线直接讲解Handler相关 主线上的东西。
但是至于ThreadLocal稍微提一下,维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本,放到这里来说,每个使用
ThreadLocal的线程,这就好比哪个线程调用了Looper.prepare()方法创建Looper的时候,






就为哪个线程保存了一个独立的Looper对象,并且多个线程调用Looper.prepare()方法去创建Looper的时候,每个线程的Looper
都是独立的,并不会互相干扰,并且每个只有一个Looper,换句话来说,只有一个Looper也只有一个MessageQueue,因为Looper内部
维护着一个MessageQueue,即消息队列。
我们知道一开始我们在构造方法中看到,通过Looper.myLooper()来获取Looper是很有可能为空的,所以既然ThreadLocal具有get方法
那是不是也有put或者set这样方法设置一个Looper呢?
我们找找看在Looper中是不是有这样的方法给sThreadLocal设置了这样一个Looper呢?
我们发现在Looper中,真有这样一个方法调用了sThreadLocal的set方法:

sThreadLocal.set(new Looper(quitAllowed));

 /** 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));
}


就是这个方法,Looper中只有这个方法调用了sThreadLocal的set方法来设置一个Looper,可是通常我们在Activity、Service
等其他主线程空间创建Handler的时候也没有去调用Looper.prepare()和Looper.prepare(boolean);方法,但是创建的时候,也没有
提示报错抛出博客最开始贴的代码中说的"不能在没有调用Looper.prepare()的子线程中创建Handler"。
那么主线程是怎么做到呢?那是不是主线程启动的时候,是不是调用了这个方法?那她在哪里调用的呢?
我们知道一个android app启动的时候,主线程是在的入口是ActivityThread的main方法的,我们去看看ActivityThread的main方法
是不是做了上面这样的操作呢?

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    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());

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}


我们在main方法里面并没有找到调用Looper.prepare()方法的地方,可是我们发现了一个很相似的方法,Looper.prepareMainLooper(); 没错就是这个方法,这个方法具体是怎么实现
的呢?

/**
 * 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();
    }
}


看看,这个方法第一行就是我们要找的prepare()方法,prepare方法就是去创建了一个Looper对象,并且设置给了sThreadLocal对象保存。
看到这里我们就知道为什么我们在主线程直接使用无参数,默认的构造方法创建的Handler不会抛出异常的原因了。
是的,Looper对象的问题算是搞定了,那么并没有地方去轮询消息分发消息啊,只是创建了一个Looper对象而已?看到这里还是一脸雾水对吧。
但是我们主线程创建的Handler发送消息,就能在handleMessage方法中处理,这是为啥?我们不妨接着ActivityThread的main方法,往下走,
你会发现,最后Looper.loop(); 从字面上来理解,loop本身具有循环的意思,是的没做,这个就是启动Looper的循环遍历消息的方法。
具体怎么循环的呢?我们直接来看看代码。

/**
 * 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
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        final long traceTag = me.mTraceTag;
        if (traceTag != 0) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }
        try {
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        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();
    }
}

这是一个静态方法,首先通过myLooper()方法取出当前线程对应的Looper对象,然后取出这个对象的MessageQueue对象,在无限的for循环
中,调用queue.next()方法获取Message对象,然后通过得到Message对象的target变量(即与之对应的Handler对象),通过调用
Handler的dispatchMessage(msg)方法,一样的字面意思,就是分发消息,所以在主线程中调用Looper.loop()方法轮询分发的消息,那么他就当然在主线程中执行消息任务,所以这里我们就知道了,如果我们
要在子线程中创建Handler,就必须在子线程中run方法中去调用Looper.prepare()方法创建一个Looper,然后最后还必须调用Looper.loop()方法去轮询分发消息。
这样我们在在子线程中创建的Handler,发送消息,和处理消息,就都在线程中了。
毫无疑问,我们直接来看这个dispathcMessage()方法:
/**
 * 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的callbak成员变量是否为null,Message的callback成员变量是一个Runnable对象,我们知道Runnable
对象有一个run方法,最后在handleCallback方法中直接执行了Message成员对象callback的run(),方法。如果Message没有设置
callback的话,即为null,就会走else语句中来,就会判断,Handler是否设置了callback,其实我们在最开始创建Handler的时候
发现,在构造方法中部分构造方法可以接收一个Callback接口类型的回调对象。
/**
 * 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);
}

是的很简单的一个接口,在那个else语句中,如果当前有callback,就直接调用了callback的handleMessage(Message)方法,好熟悉的
统一的一个方法,所以外界可以实现一个Callback对象,Override handleMessage()方法,在这个方法中,做一些特定的业务。
再回到主线,不管if还else,最后都会调用Handler的handleMessage方法,到这里大家应该都很熟悉了把。我么来直接看看这个方法。
/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

是的,这个方法更加简单的离谱,他什么都没有做,所以,我们在使用handle的时候,可以直接覆盖这方法,这样Looper把消息
分发出去之后,处理消息的时候,就能执行到我们的逻辑。
其实呢,到这里我们的消息分发处理过程就说完了。

四、使用Handler的好处和作用

	我们知道,Android中,在UI线程中做耗时的操作,会导致UI线程
无法及时(或者实时,或者阻塞UI线程)更新界面UI,就会出现ANR现象,
为了出现这样的情况,我们业务操作都放在子线程中执行,可是android
的UI线程安全规则规定,不能在子线程中更新UI,假如你在子线程中
尝试去更新UI,会抛出异常,程序直接崩溃,这就使得google
推出了一个Handler机制,来更新UI,所以我们一般会在主线程创建一个Handler对象,然后在子线程中做耗时任务,
好使任务完了之后,就可以拿到Handler对象的引用,来发送消息到主线程去更新UI.


至于使用Handler的好处,很显然,决绝UI线程的安全性问题,
更新UI的同步实时问题,也实现了线程间的通信问题,还一个好处就是使得代码更加灵活健壮。

五、总结使用Handler的时候需要注意的一些细节

	1.在子线程中,如果没有调用Looper的prepare()方法去创建
一个Looper的话,在该线程中创建Handler会报出异常,如果调用了
prepare()方法之后,你还必须去调用Looper的loop()方法,否则
你发的消息,都将得不到处理,因为loop()就是开启消息轮询提取发送的
启动器。
       2.如果你自定义一个线程,在线程中使用Handler和Looper,
		在你对该线程没有需要的时候,你应该调用该线程中Looper对象的
	looper.quit()方法,否则该方法一直处于无限循环状态,一般情况下也是需要消耗资源的。
       3. Looper.myLopper()方法可以获取到当前线程对应的Looper
	4.Looper.getMainLooper()可以获取到主线程中的Looper,那就意味着,我们除了在主线程中创建Handler,在其他子线程中
通过使用Handler的Handler(Looper)构造方法,传递主线程的Looper也能在子线程中创建一个在子线程中执行任务的Handler。

六、Handler、Looper、MessageQueue,Message的关系和区别

最后,我们根据前面关于对源码的跟读,自然而然对这三者的关系很清楚的了。
Handler: 是一个发送消息和处理消息的工具。
Looper: Looper是消息存储控制中心,Looper内部维护这一个消息队列MessageQueue,调用loop()方法就开启了消息队列的无限
循环的遍历提取分发。
MessageQueue:消息队列,是一个用来存储Message的队列载体,他被Looper控制。
Message: Handler发送的消息,都通过这个对象来进行封装,这是一个消息主体,记录的消息的细节和承载着一些数据。

七、针对Handler 衍生扩展到HandlerThread

	前面我们谈过自定义一个Thread,并且支持在这个线程中创建Handler,
这样的情况下,我们必须在线程起来的时候调用Looper.prepare()方法去创建Looper
和调用Looper的loop()方法,才能实现这样的功能,但其实后呢,后来google考虑到了
这一点,自己帮我实现了一个这样的东西,即HandlerThread,其实我们可以把她看成一个工具类
,用来实现线程间的通信,其实他的实现细节,还真的就跟我们说的一样的,不信来看看吧。
首先HandlerThread是一个继承了Thread类的对象。



/**
 * 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;
}


我们发现,在这个HandlerThread的run方法中,一开始就调用了Looper的prepare()方法,又在最后调用了Looper的loop()方法。使用HandlerThread的一个优点在于,在Looper prepare的时候,还有一个回调onLooperPrepare方法,这个方法空实现,所谓的空实现,明摆就是让我们自己去覆盖了,我们完全可以在创建HandlerThread的时候去覆盖就好了,这样就Looper prepare的时候可以做点什么任务了。但是住的注意的是,我们在不需要使用HandlerThread的时候,要去调用HandlerThread的quit()方法,退出Looper的循环,释放资源让应用更加性能好。

/**
 * 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;
}



写到这里,这篇博客基本写完了,转载请注明出处。



 







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值