从源码的角度分析Android中的Handler机制的工作原理

                          通过对源码的查看,特此记录Android中handler机制的工作方式

 

我们要在Android中使用Handler机制,必须要经过如下三个过程

  1. 在一个线程调用   Looper.prepare()   来创建一个Looper. (主线程不需要,因为源码中在Activity创建的时候已经调用过一次了)
  2. 调用   new Handler()   创建一个   Handler.
  3. 调用   Lopper.lopp()   开始进入死循环不停的从   MessageQueue   中取出消息然后发送给   Handler   处理.

 

下面我们从源码的角度去查看为什么要经过这三个过程Handler机制才能正常工作:

源码的 Looper.prepare()  干了什么:

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));
}
  • 我们看到,在最后一行中的    sThreadLocal.set(new Looper(quitAllowed))   给一个ThreadLocal变量设置了一个 Lopper  对象,这样就造成了这个线程和这个  Lopper  关联起来了.

从源码中发现,在Handler机制中的   MessageQueue   是由   Lopper  来维护的, 为什么? 因为源码中有这么一段:

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

所以经过源码中的步骤,一个线程就和一个 Lopper 关联起来了,而这个 Lopper 又维护着一个 MessageQueue .

 


源码的 new 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;
    }

这是    Lopper.myLopper  的源码:

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
  • 天哪噜,我们看到,,,之前设置给那个  ThreadLocal  变量的   Lopper  在这里 马上就被使用  sThreadLocal.get() 方法被  Handler 获取到了.
  • 然后我们看到,获取到  Looper 之后马上又获取了 Looper 的 MessageQueue.

所以通过这一步我们看到, 源码帮我们把 我们之前调用的 Looper.prepare 创建的 looper 对象和一个 Handlder 关联起来了,并且Handler 还获取了由 Looper 维护的 MessageQueue!  接下来就可以干大事了!!!

 


源码的  Lopper.lopp()  干了什么(比较多,贴精华部分):

     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);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
}

这里是 Message 类的部分源码,方便理解上面的代码:

class Message implements Parcelable {
  Handler target;
}
  • 我们看到,在loop方法中,也同样是调用了 myLooper 获取了 第一步创建的一个和线程关联的 looper 
  • 然后获取了这个 looper 的 messagequeue ,之后就会进入一个死循环.
  • 在这个死循环中,会不停的去调用 message.next ,来获取下一个 message (message队列使用链表实现的.)
  • 获取到一个 message后,就会调用 message 的  target.dispatchMessage  来发送消息到handler, 通过上面 message 类 ,我们看到 target变量就是一个 Handler.

 

到了这里,有读者肯定会问,这个 Message 中的 Target 是怎么来的呢, 这个 Message 是如何和一个 Handler 关联起来的呢? 

  • 我在这里解释一下,无论我们通过 handler 的post 方法 还是 sendMessage 方法来发送一条消息,在源码中,都会跳转到 Handler 中的如下代码中:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

首先注意这一段代码是 Handler 中的源码 ,看方法名字就知道,是往之前获取的 MessageQueue中插入消息, 然后最重要的就是

 msg.target = this  这句, 通过这句话,这个 Message 就和这个Handler关联起来了,然后在 loop 中就会把这个 message 发送给这个 handler 进行处理!!!


                                                                     总结

 

  1. 通过上面对源码的分析,我们知道要让Handler机制能够正常工作,必须要有一个looper,然后Handler会的往这个looper的MessageQueue中发送消息,之后再调用loop不停的去MessageQueue中取出消息发送给和这个Message关联的Handler进行处理.
  2. 比如我们在线程中调用了 Looper.prepare 那么这个 Looper 就会和该线程关联,然后我们在其他线程中调用 Handler 发送消息, 这个消息自然会被插入到创建 Handler 的那个线程的 MessageQueue 中 ,然后再让 Handler 进行处理 ,这样就实现了 Android中的线程通信原理.
  3. 同时我们也可以从 java 引用的角度来思考 Handler 机制是如何实现的:
  •  第一步 :  Lopper.prepare() 会导致一个线程的 ThreadLocalMap 中持有了一个 Lopper 的引用.
  •  第二步  : new Handler() 导致 Handler 会持有当前运行这句话的那个线程的 Looper 的引用, 然后当我们调用 handler 发送 message 时, 每一条 message 都会持有 handler 的引用(即 message 的 target 成员变量)
  •  第三步 :  Lopper.loop() 会从从当前正在运行这句话的线程中获取 Lopper 引用, 然后进入死循环获取 Looper 中的 message, 然后调用 message.target.dispatchMessage() 最关键的就是这一步,无论这个 Handle r在哪个线程创建,关键的是当前正在运行这句话的线程获取了 handler 的引用, 从而通过 handler 的引用调用了 handler 的成员方法, 从而实现了把 Message 发送到了目标线程.

这里顺便说一下为什么在子线程中创建一个 Handler 而没有调用 Looper.prepare 会报错的原因,其实很简单,就是源码中的一段:

       mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }

 如果有误,欢迎评论指导,谢谢!!

你可能感兴趣的:(Android开发)