Handler

#建议跟随本笔记读源码、读官方文档说明,且牢记消息机制中涉及到的四个部分:Handler、Looper、MessageQueue、Message,分析中会着重强调它们之间的关系)

##请仔细阅读官方文档中关于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();
  }
}

我们的分析过程就是围绕这几行代码(首先注意到一点,这段代码是跑在子线程中的)。下面开始:
###1. Looper.prepare()方法:可以把Looper源码打开,先不去看这个prepare方法,先找到Looper的构造方法:

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

发现是私有的,即我们不能够在外部自己new出对象。再看这个无参prepare方法:

public static void prepare() {
    prepare(true);
}

发现会调用一个参数的prepare()方法:

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

先注意到这里new了Looper对象了。这是第一次看到我们整个消息机制的四个部分的其中一个对象。

这里有一个***sThreadLocal*** 。不好解释,解释起来太长,给大家一个结论吧:首先明确一个叫做以线程为作用域变量的概念,ThreadLocal这个类型可以在不同的线程中维护一套数据的副本并且彼此互不干扰。(我是阅读《开发艺术探索》理解的)

### 2020.07.08更新,对于ThreadLocal的理解可参考笔者此篇

不管怎么说,程序到这一步,我们已经生成拿到了Looper对象。

###2. 再回到示例代码(new Handler一行):这里需要我们重写handleMessage()方法,有一个Message对象的参数,可以看一下Handler类关于这个方法的实现:

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {

}

一看发现为空,从上面的文档注释也可以知道,子类是需要重写这个方法,在这个方法中实现具体的处理消息的逻辑(比如更新UI)

###3. 从new Handler()对象开始:(使用无参构造作为分析入口)

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

无参构造会调用两个参数的构造方法:

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

注意标出的两行代码:

a. mLooper = Looper.myLooper();

b. mQueue = mLooper.mQueue;

从第一个开始:调用Looper.myLooper()方法,这时我们可以去看一下这个方法是干什么的。

/**
 * 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,有get肯定有set,set实际上已经在前面见过了,(第1条prepare()方法中),从某种意义上讲,我们大致可以知道这里实际上就是返回一个Looper对象的引用,这个对象就是前面在prepare方法中new出来的。好,返回这个Looper对象的引用给了谁?mLooper。这是Handler的一个实例变量。那到这一步,我们的Handler对象和Looper对象是不是就建立联系了,即我们可以通过在Handler类中通过mLooper调用Looper对象中的方法了。


再往下看第二个红框:**b. mLooper.mQueue**,在Looper的源码中找到它:
**final MessageQueue mQueue;**
发现是个MessageQueue类型的引用,把这个引用赋给了Handler的成员mQueue,毫无疑问这个mQueue也是MessageQueue类型。那么这两个引用都指向哪个对象呢?或者说Looper中的mQueue是什么时候被初始化的呢?可以再回到Looper的私有构造方法:
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

嗯,在这里new出来了。

到这里,已经出现了Handler,Looper,MessageQueue三个组成部分了,而且这三者之间的关系是:组合关系,即Handler中同时持有Looper对象的引用和MessageQueue对象的引用,Looper中持有一个对MessageQueue对象的引用,对于Looper和MessageQueue它们的关系更紧密,因为是在Looper的构造方法中创建了MessageQueue对象,即这两个对象是成对出现的。关系图如下:

还差一个Message了,不要着急,下面我们马上开始sendMessage方法的分析。(注意,示例代码还有一行)

###4.sendMessage()方法:
首先这个方法需要传入一个Message对象,关于Message对象的创建有多种方式:由于构造方法是public的,所以可以自己new出来,但是官方建议:

While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.

实际上底层维护了一个Message对象池(消息池)。

进入sendMessage()方法的实现:

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

再跟进:

/**
 * Enqueue a message into the message queue after all pending messages
 * before (current time + delayMillis). You will receive it 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.  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 final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

再跟进:

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

可以停下来:这里就用上了Handler的mQueue成员(即一个消息队列,即前面在Handler构造方法中建立关联的那个MessageQueue对象)。再进enqueueMessage()方法:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

先看第一个红框:msg.target = thismsg,不就是我们从sendMessage传进来的那个Message对象。将这个Message对象的target成员赋值为this,this是谁?当前还是在Handler类中,那么这个this不就是Handler对象了嘛。再看这个target的定义:

/*package*/ Handler target;

那么我们的Handler和Message也建立关联了。现在补充完善前面画出的前三者之间的关系图:

好,再看第二个红框:***return queue.enqueueMessage(msg, uptimeMillis);***

这里流程已经从Handler类中跳到了MessageQueue中,我们来看enqueueMessage方法的实现,代码很多,我们就看这几行:

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;

给出个结论吧,学过数据结构都知道,实际上这几行代码就是在执行单链表的插入操作,也就是说MessageQueue底层维护的Message型的单链表。那到这里,我们的消息已经放到了消息队列中。

###5.再来看示例代码的最后一行:
Looper.loop();

进入这个loop方法:

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

首先这里是个死循环,只有next方法返回null才会退出,这也就应征下面这段话:

Looper:是每个线程的MesssageQueue的管家,调用Looper的loop方法后,就会进入到一个无限循环当中,每当发现MessageQueue中存在一个消息,就会将它取出,并传递到Handler中的handleMessage()方法中。每个线程中只会有一个Looper对象。

看代码旁边注释:might block。即可能会阻塞。那next的阻塞也就会造成loop的阻塞。再来看next方法:

if (prevMsg != null) {
      prevMsg.next = msg.next;
} else {
      mMessages = msg.next;
}

msg.next = null;

这几行是不是就是在执行链表结点的删除操作。在回到loop方法:
msg.target.dispatchMessage(msg);

注意这一行,调用了msg.target.dispatchMessage()的方法。这个msg.target是在哪里赋值的?前面已经提到,在

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

中的msg.target = this;

对,就是那个发送此消息的Handler对象,现在在loop方法调用了这个Handler对象的dispatchMessage()方法,现在流程又回到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(),就是我们在创建Handler对象时重写的那个handleMessage方法。到这里,我们的消息机制的整个流程就走完了。从sendMessage用来发送消息,最终又回到handleMessge方法中来处理消息。嗯,我已经对整个流程清楚了。


现在我们来看这样一个问题,就是我们在编写更改主界面时,并没有像示例代码中那样,先调用prepare(),最后再调用loop方法,这是为什么?这个时候,我们需要在Android源码中搜索ActivityThread.java源文件,打开它,查找“public static void main”,大概在4900多行,会找到一个熟悉的方法,main方法,

兴奋之余,再来看这个红框代码:调用Looper类的静态prepareMainLooper()方法,在Looper类中找到它的实现:

//终于在Android中找到久违的main方法了
public static void main(String[] args) {
    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());

    Security.addProvider(new AndroidKeyStoreProvider());

    Process.setArgV0("<pre-initialized>");
	
	//着重看这行代码
    Looper.prepareMainLooper();

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

兴奋之余,再来看这个红框代码:***Looper.prepareMainLooper();***

调用Looper类的静态prepareMainLooper()方法,在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();
    }
}

注意红框 prepare(false);//着重看这行代码

在这里调用了prepare()方法。找到了prepare方法,接下来去找loop方法在哪里调用的,再回到ActivityThread中的main方法:

Looper.loop();

所以,我们的整个步骤还是和示例代码是一样的,哪怕是主线程,也不会违背。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值