Handler机制介绍

这篇文章介绍一下Handler的原理,仅用于个人适当回顾学习。

一.功能介绍

1.用于线程间的通讯,可以通过handler进行切换UI线程进行绘制UI。
2.用户控制延时的消息传递。

二.重要的类介绍

1.Message:

数据载体,通过handler进行数据传递的对象就是message。可以存入多个参数。

2.MessageQueue:

其实从名字就可以看出,这是一个队列,平时我们使用handler进行消息传递的时候,事实上是将message对象放入当前队列中。

3.Looper

既然有队列,那么肯定有对队列进行操作的管家。而looper就是这个管家。一个handler对应一个looper,一个looper内部也持有一个MessageQueue对象。

4.ThreadLocal

handler的线程间通信的关键,已经有文章介绍了,就不再这里说明了。

三.源码分析

先从构造方法看起来

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class 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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

由以上构造方法可以看出,创建Handler的时候,就获取了对应的looper。然后再通过looper获取对应的MessageQueue。

我们先分析一下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();
    }

    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。可以看到其实looper是从,ThreadLocal中获取的,而ThreadLocal刚好又可以对线程间的数据进行存储。说白了就是获取当前线程的对象。
同时看到prepare方法,其实所有的handler都是首先要创建对应的Looper对象。就是通过prepare方法。而在主线程不需要,是因为主线程已经默认帮我们创建好了这个对象。

前面我讲过looper其实是一个管家,用于处理queue中的消息,那么这个管家是如何工作的呢,我们就看下面一个来自Looper的方法

  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;
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
           try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
}

以上是我截取的部分代码,从上面可以看出,其实looper在调用loop方法后开始工作,而loop的工作方式,其实就是不断循环,如果发现queue之中有消息的话,就对消息进行处理,如果没有的话继续循环。

看明白了消息的传递,那么对于handler的消息使用就很明白了,我们看下面handler的一个sendMessage的方法。

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

相信你已经明白了吧,就是把消息存入队列queue之中,存入之后,循环中的looper对象发现queue之中多了一个消息,就对他进行处理。

刚去晚上到了一张图来,希望你能看明白


Handler机制介绍_第1张图片
20180308191240946.jpg

你可能感兴趣的:(Handler机制介绍)