嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2014-04-27 2720 次浏览 标签 : Android

注释里写了使用的一个小demo

/**
  * 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 {
	private static final String TAG = "Looper";

    // sThreadLocal.get() will return null unless you've called prepare().

    //由于ThreadLocal是静态变量,所以无论生成了多少个Looper,THreadLocal始终只有一个
    //在这ThreadLocal可以存储多个键值对
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;//消息队列成员变量
    final Thread mThread;//线程对象变量

    //我们在外面调用的Looper.prepare()
    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");
        }
        //如果值为空
        //prepare做里两件事
        //1.生成了一个Looper对象
        //2.把这个Looper对象存在了线程本地变量当中
        //ThreadLocal.set(Object obj)
        //obj是一个键值对对象,当前线程对象作为键
        sThreadLocal.set(new Looper(quitAllowed));
    }

    public static Looper myLooper() {
        return sThreadLocal.get();//取出了当前线程对象的值
    }

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//生成了一个与Looper对象与之对应的MessageQueue对象
        mRun = true;
        mThread = Thread.currentThread();
    }
}

public class Handler {

	final MessageQueue mQueue;
    final Looper mLooper;//循环的时候要使用的对象
    final Callback mCallback;
    final boolean mAsynchronous;

	public Handler() {
        this(null, false);
    }

    public Handler(Callback callback, boolean async) {
        //...

    	//mLooper里面的m是member,成员变量的意思
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//把Looper对象里面的mQueue成员变量赋值给Handler的mQueue成员变量
        mCallback = callback;
        mAsynchronous = async;
    }
}

实际Looper和Handler就是通过ThreadLoacl把两者联系在了一起,总结下: 

Looper.prepare()生成了一个Looper对象(并且在生成Looper对象的同时生成了一个与之对应的MessageQueue对象,赋值给了Looper的mQueue成员变量)然后把这个Looper对象存入ThreadLocal中去。 在使用Handler的时候,在其构造函数中,先通过Looper的myLooper方法获取到当前线程对象的值。然后赋值给Handler的mLooper的这个成员变量,然后把Looper的mQueue成员变量的值赋值给Handler的mQueue成员变量。

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表