Android-源码解析Handler&Looper

Handler是可以用来发送消息,或者一个Runable;消息/Runable可以在指定的线程(由Handler中的Looper决定)中接受/执行;
MessageQueue:消息队列,用来存放消息的
Looper:用来循环遍历消息队列中的消息,并负责消息的分发

我们看看使用Handler常用示例代码(如下


public class TestActivity extends Activity {

    private Handler mHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
                case caseA:
                    doSomeThingA();
                    break;
                case caseB;
                    doSomeThingB();
                    break;
                default:
                    break;
            }
        }
    };
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sendMessage();
    }

    private void sendMessage() {
        Message msg = Message.obtain();
        msg.what = caseA;
        msg.obj = data;
        mHandler.sendMessage(msg);
    }
}

我们可以看到mHandler变量作为成员变量,覆写了handleMessage方法,且是通过无参构造器创建出来的;
在onCreate方法调用了sendMessage方法,这样消息最终被传送到handlerMessage中;下面我们结合Handler部分源码看看消息是如何一步一步到达Handler的handleMessage方法里的。

TestActivity类中的sendMessage方法中发送消息后,调用了mHandler.sendMessage(msg),也就是如下代码,

public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

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

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

我们从上述源码可以看到,handler发送的消息最终是把消息放到消息队列中,之后就没做任何事情了,那么问题来了

  1. 那么消息队列是在什么时候创建?

    其实每个Looper都包含一个消息队列成员,而消息队列也是在Looper构造器时被创建;

    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
    }
  2. 最终消息是如何分发到handlerMessage中?

我们看到Handler类中包含了Looper 和 消息队列成员变量,它们都是在构造器中被赋值(见下面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());
            }
        }

        //获取当前线程的Looper对象
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }

        //从Looper对象中获取消息队列
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

因为示例代码中Handler对象是在UI线程中创建,而系统在初始化时会自动调用Looper.prepareMainLooper方法,该方法帮我们创建好了主线程的Looper对象(所以在UI线程中我们不需要主动调用Looper.prepareMainLooper去创建Looper对象);创建Looper对象后会启用loop方法,它会不断循环读取消息队列的消息。

我们看下Looper源码:

package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
import android.util.Printer;

/**
  * 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.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  *
  * <p>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.
  *
  * <pre>
  *  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();
  *      }
  *  }</pre>
  */
public final class Looper {
    /*
     * API Implementation Note:
     *
     * This class contains the code required to set up and manage an event loop
     * based on MessageQueue.  APIs that affect the state of the queue should be
     * defined on MessageQueue or Handler rather than on Looper itself.  For example,
     * idle handlers and sync barriers are defined on the queue whereas preparing the
     * thread, looping, and quitting are defined on the 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.class

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

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

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

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

            //target其实就是Handler,此处就是将消息传递到Handler中dispatchMessage方法中
            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();
        }
    }

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

    /**
     * Return the {@link MessageQueue} object associated with the current
     * thread.  This must be called from a thread running a Looper, or a
     * NullPointerException will be thrown.
     */
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }

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

我们可以看到上述代码中loop方法,其内部就是不断从消息队列中取消息,最终调用msg.target.dispatchMessage(msg);这里的target其实就是handler对象,也就是Handler的dispatchMessage方法;那么dispatchMessage内部是怎么实现?(看下面源码)

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
        //如果Message中的Runnable不空,直接调用Message的Runable.run方法
            handleCallback(msg);
        } else {
        //如果Handler中构造器传入了CallBack不为空
            if (mCallback != null) {
            //如果CallBack不为空且handleMessage返回为true,直接返回(不执行handleMessage方法了)
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    private static void handleCallback(Message message) {
        message.callback.run();
    }

    public interface Callback {
        public boolean handleMessage(Message msg);
    }

我们的示例代码中发送的message的callback没有赋值所以为null,且我们的mHandler是无参构造的所以mCallback其实也是为空,所以最终执行到Handler的handleMessage方法;整个大体流程就是这样;

我们可以看到其实dispatchMessage方法运行在哪个线程其实是由Looper.loop决定的,至此整个流程逐渐清晰明朗起来了

梳理下流程:

Created with Raphaël 2.1.0 Handler Handler MessageQueue MessageQueue Looper Looper (1)sendMessage (调用在A线程) 最终是将消息添加到消息队列中 (2) Looper不断从消息队列中取消息 (3)dispatchMessage(运行在loop调用的线程) (4)处理消息

通过Looper&Handler来达到线程间通讯

上面示例代码演示消息最终在UI线程被消费处理掉,如果要将一个消息/Runable传递给一个线程我们该如何做呢?我么可以这样做

class LooperThread extends Thread {

        private Handler mHandler;

        @Override
        public void run() {
            super.run();

            //为当前线程创建一个Looper对象
            Looper.prepare();

            //handler会获取当前线程绑定的Looper对象
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                }
            };

            //循环分发消息队列中的消息
            Looper.loop();
        }
    }

首先定义一个LooperThread,我们覆写run方法,并对该线程绑定一个Looper对象和一个Handler对象,这样在外部我们可以通过Handler对象将消息/Runable交给Handler的handlerMessage处理了;这样就达到了其他线程消息交给此线程处理目的,这其实就实现了线程间通讯了。

猜你喜欢

转载自blog.csdn.net/dbs1215/article/details/72982803