Handler Looper Message的源码分析

Handler

Handler是用来分发和处理消息的,通常我们创建Handler都是使用其无参数的构造方法


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

其内部调用的是2个参数的构造方法


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) {
          	//大概的意思就是创建Handler的匿名内部类,成员类,局部类的时候会给出下面log的提示
             Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                 klass.getCanonicalName());
         }
     }
	 //获取当前线程的Looper对象,如果是在UI线程(四大组件)中创建Handler,那么这里拿到的就是主线程的Looper
     mLooper = Looper.myLooper();
     if (mLooper == null) {
     	//在子线程中创建Handler如果没有事先初始化Looper,是拿不到Looper的,因此会抛异常
         throw new RuntimeException(
             "Can't create handler inside thread that has not called Looper.prepare()");
     }
     //记录Looper对象内的MessageQueue消息队列
     mQueue = mLooper.mQueue;
     //记录传递进来的callback接口,注意这里的Callback接口是定义在Handler类内部的.
     mCallback = callback;
     //记录是否是异步,默认构造方法传入的是false,表示同步处理消息
     mAsynchronous = async;
 }

//内部接口
public interface Callback {
    public boolean handleMessage(Message msg);
}

分析上面的源码可以发现,在new Handler的时候,内部会得到一个Looper对象,以及该Looper的MessageQueue对象.
同时提到了 "Can't create handler inside thread that has not called Looper.prepare()");这个异常,仅当Looper获取为空的时候抛出.

另外,参数async表示此创建的Handler是否用于处理异步消息,如果是则需要通过Message的方式来异步处理,而如果不是,那就通过postRunnable的方式来处理同步的消息.


Looper

上面创建handler的时候提到了Looper,那么现在我们来分析下Looper的源码

public final class Looper {
    private static final String TAG = "Looper";

    // 通过ThreadLocal绑定Looper对象到当前线程,默认情况下sThreadLocal.get()会返回null,除非你事先调用了prepare()方法.
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    // 主线程的Looper对象,在主线程中创建Handler,默认会初始化一个Looper与主线程绑定
    private static Looper sMainLooper; 
	//消息队列,每个Looper对象内部都有一个消息队列
    final MessageQueue mQueue;
    //当前线程
    final Thread mThread;
	//log输出对象
    private Printer mLogging;

     /** 
     * 初始化Looper,给当前线程绑定一个Looper对象,该方法创建的Looper,默认是支持结束loop的
      */
    public static void prepare() {
        prepare(true);
    }
	/**
	* 私有的初始化Looper对象方法
	* 参数quitAllowed表示是否支持结束loop,通过调用quit()或者quitSafely()方法进行结束
	*/
    private static void prepare(boolean quitAllowed) {
    	//一个线程只能绑定一次Looper
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //创建一个Looper,并将Looper绑定到当前线程中
        sThreadLocal.set(new Looper(quitAllowed));
    }
	
	/**
	* 私有构造方法,因此创建Looper必须要通过prepare方法创建
	*/
	private Looper(boolean quitAllowed) {
		//初始化该Looper的MessageQueue对象,Handler发送消息的时候会用到mQueue,它用于存储Handler发送的Message
        mQueue = new MessageQueue(quitAllowed);
        //获取当前线程,作为sThreadLocal的key,value就是该绑定的Looper对象
        mThread = Thread.currentThread();
    }

	
    /**
     *初始化主线程的Looper对象,由android系统调用,不需要我们自己调用
     */
    public static void prepareMainLooper() {
    	//初始化Looper,主线程创建的Looper是不需要结束loop的,如果手动调用结束方法会抛出异常
        prepare(false);
       
        //主线程的Looper只能由android系统初始化,我们自己初始化会抛异常
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
             //记录主线程的Looper
            sMainLooper = myLooper();
        }
    }

    /** 获取主线程的Looper
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

 /**
     * 返回与当前线程相关Looper对象,如果返回null,则说明当前线程没有关联Looper
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

  
    /**
     * 返回当前线程绑定的Looper对象内的MessageQueue ,这个必须在Looper中运行的线程中调用,否则会报空指针异常
     */
    public static MessageQueue myQueue() {
        return myLooper().mQueue;
    }
	

    /**
     * 轮询MessageQueue中的Message,如果是子线则需要手动调用loop方法轮询处理消息
     */
    public static void loop() {
    	//1.获取当前线程绑定的looper对象
        final Looper me = myLooper();
        if (me == null) {
        //在子线程中创建Handler,如果没有调用Looper.prepare(),那么myLooper()方法是获取不到Looper对象的.则会抛异常,
        //而主线程由于系统已经调用了prepareMainLooper方法,因此没有这个问题
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //2.获取Looper的消息队列
        final MessageQueue queue = me.mQueue;

        // ...

        for (;;) {
       		 //3.这里是死循环,从MessageQueue中遍历所有的Message对象
            Message msg = queue.next(); // might block (next方法是阻塞的方法)
			
			//消息为null,结束loop
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

           // ...
           
           /* 4.获取Message所关联的target,这里的target其实就是Handler对象,后面会解释
           调用关联的Handler对象的dispatchMessage方法,将消息传递给Handler去处理*/
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // ...

			// 释放消息,清空Message中保存的各种引用
            msg.recycle();
        }
    }

   
    
    /**
     * 判断当前Looper内的线程是否就是当前线程
     */
    public boolean isCurrentThread() {
        return Thread.currentThread() == mThread;
    }

    /**
     * 非安全的退出Looper,会导致loop方法终止,退出时并不保证消息队列中的所有message都已处理完毕
     */
    public void quit() {
        mQueue.quit(false);
    }

    /**
	* 安全的结束Looper,loop方法仅当消息队列中的所有message都处理完毕后才终止,但是不包括延时处理的message
     */
    public void quitSafely() {
        mQueue.quit(true);
    }

    

    /**
     * 获取与之Looper关联的线程对象
     */
    public Thread getThread() {
        return mThread;
    }

  ...

通过分析Looper的源码,我们可以了解到Looper类是用来轮询当前线程相关联的Message对象的,每轮询一个message,就会通过该message持有的Handler的引用也就是target去处理消息,具体是通过dispatchMessage方法分发处理消息,稍后会讲到.

默认创建的线程是没有与任何Looper进行关联的,必须要先通过Looper的prepare()静态方法来创建并通过ThreadLocal进行关联绑定,接着轮询处理消息的时候必须要手动调用loop方法进行处理.


子线程创建Handler

下面是一个经典的子线程中创建Handelr,并通过Looper轮询和处理消息的例子:

class LooperThread extends Thread {
    public Handler mHandler;
    public void run() {
    	//初始化Looper
        Looper.prepare();
        //创建处理消息的Handler,最开始已经分析过子线程中创建Handler,必须要先有Looper
        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };
        //开始轮询
        Looper.loop();
    }
}

在主线程中创建Handler的,系统已经帮我们完成了Looper.prepare();和 Looper.loop();的工作了,因此我们可以直接使用Handler.


疑问

分析Looper源码的时候有以下2个疑问待解决,定位到loop方法中的msg.target.dispatchMessage(msg);

1.target是何时与Message进行关联的呢?
2.dispatchMessage是如何处理轮询出来的消息(message对象)?

target的由来

target是Message对象的一个属性,要知道它是啥时候赋值的,那么我们可以先Message的创建说起,Message有多中方式创建,通过空参的构造方法创建,或者通过其多个静态的obtain方法创建.
空参的构造方法内一行代码也没有,看不到有啥有用的线索,obtain方法倒是有几个可以直接看出对target的赋值声明,例如:

...
public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}


public static Message obtain(Handler h, Runnable callback) {
    Message m = obtain();
    m.target = h;
    m.callback = callback;

    return m;
}

...

但是这些静态方法并不是创建Message的唯一途径,因此都不能保证target就已经关联了Handler对象,那么我们只能从Handler的sendMessage方法入手了.

public final boolean sendMessage(Message msg) {
	//继续往下调用sendMessageDelayed方法,该方法是一个延时发送消息的方法,这里传递0表示马上发送.
	return sendMessageDelayed(msg, 0);
}

接着sendMessageDelayed方法

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
	if (delayMillis < 0) {
	 	delayMillis = 0;
	}
	//继续往下调用sendMessageAtTime,功能是一样的,名字不同而已.
	return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

}

接着sendMessageAtTime方法

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
	//判断此时的Looper的MessageQueue是否为null,是者打印警告log
	MessageQueue queue = mQueue;
	if (queue == null) {
	    RuntimeException e = new RuntimeException(
	            this + " sendMessageAtTime() called with no mQueue");
	    Log.