欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android Handler源码解析

程序员文章站 2022-07-14 16:46:40
...

之前看过好几次Handler源码,但是时间一久就印象模糊了,还是自己写笔记好

涉及Looper、ThreadLocal、Thread

一、Handler

    1、handler创建

public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;//mQueue实际上是looper的mQueue
        mCallback = callback;
        mAsynchronous = async;
}

    2、handler发送消息时,往当前线程绑定的looper的messageQueue中塞消息

   public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //这个mQueue是创建handler时,从传入的looper/如果是主线程就是Looper.getMainLooper(),looper.mQueue;
        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;//msg.target 就是当前的handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//把msg塞入looper的消息队列中
   }

二、Looper

    官方介绍

/**
 *  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();//第三步
 *      }
 *  }
 */
1、Looper.prepare();做的事情
        1)创建looper对象
        2)在looper中创建消息队列 messageQueue
        3)将looper与当前线程通过looper的成员变量threadLocal实现绑定

 

public final class Looper {
    /**
     * sThreadLocal是Looper中定义的静态成员变量,两者是互相都是唯一的
     * threadLocal.set(looper),是把threadLocal作为key,当前looper作为value,存入当前线程的threadLocalMap中
     * threadLocal.get(),currentThread.threadLocalMap.get(threadLocal),根据threadLocal拿到存在当前线程的threadLocalMap中的looper
     */
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    final MessageQueue mQueue;//looper的消息队列
    final Thread mThread;
    private Printer mLogging;
    private long mTraceTag;
    
    public static void prepare() {
	prepare(true);
    }

    /**
     * @param quitAllowed  MessageQueue是否允许退出
     */
    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));
    }
			
    private Looper(boolean quitAllowed) {//prepare()中创建了消息队列
	mQueue = new MessageQueue(quitAllowed);
	mThread = Thread.currentThread();
    }
    ...
}

2、looper与线程一一对应关系的实现

public class ThreadLocal<T> {
	...
	public T get() {
	    Thread t = Thread.currentThread();//获取当前线程
	    /*
	     * 每个thread内部都有threadLocalMap,key为:threadLocal 在这里value为:looper
	     * 获取当前线程的threadLocalMap,取出threadLocalMap中与当前threadLocal对应的looper
	     */
	    ThreadLocalMap map = getMap(t);
	    if (map != null) {
		ThreadLocalMap.Entry e = map.getEntry(this);
		if (e != null)
			return (T)e.value;
	    }
	    return setInitialValue();
	}
			
	public void set(T value) {
		Thread t = Thread.currentThread();//获取当前线程
		ThreadLocalMap map = getMap(t);//拿到当前线程的threadLocalMap
		if (map != null)
		/*
		 * 把当前threadLocal作为key,传入的值作为value,存入threadLocalMap中
		 * 由于threadLocalMap是属于当前线程的一个成员变量,所以value实际是存在当前线程中的
		 */
			map.set(this, value);
		else
			createMap(t, value);
	}
	...
}

3、在UI线程使用handler不用Looper.prepare()的原因

public final class ActivityThread {
	public static void main(String[] args) {
		...
		Looper.prepareMainLooper();//在此处调用了prepare();
		ActivityThread thread = new ActivityThread();
		thread.attach(false);//主要是获取AMS接口 然后设置ApplicationThread 的接口 给AMS和应用程序通信
		if (sMainThreadHandler == null) {
			sMainThreadHandler = thread.getHandler();
		}
		if (false) {
			Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
		}
		// End of event ActivityThreadMain.
		Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
		Looper.loop();//此处调用了loop();
		throw new RuntimeException("Main thread loop unexpectedly exited");
	}
}

4、Looper.loop();遍历队列中的消息,并回调handleMessage(msg)

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 (;;) {//死循环,不断的从looper的messageQueue中取出消息
		Message msg = queue.next(); // might block
		if (msg == null) {//没消息时直接return,停止循环
			return;// No message indicates that the message queue is quitting.
		}
		// This must be in a local variable, in case a UI event sets the logger
		final Printer logging = me.mLogging;
		if (logging != null) {
			logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
		}
		final long traceTag = me.mTraceTag;
		if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
			Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
		}
		try {
			//msg.target 这个target就是定义的handler,此处分发消息,会回调到handler的handleMessage(Message msg),处理消息
			msg.target.dispatchMessage(msg);
		} finally {
			if (traceTag != 0) {
				Trace.traceEnd(traceTag);
			}
		}
		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();
	}
}