Android 中 Handler,Looper,HandlerThread 的关系分析
最近项目中要用到 HandlerThread,对其的用法一直不甚了解,趁着五一放假就花了点时间研究一下,顺便备份在博客上。
因为刚开始研究的是 HandlerThread,所以我们就从 HandlerThread 入手,我们先来看一下它的源代码
/*
* Copyright (C) 2006 The Android Open Source Project
*/
package android.os;
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;//线程优先级
int mTid = -1;//TID
Looper mLooper;//Looper成员变量
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;//构造函数,设置默认线程优先级
}
/**
* Constructs a HandlerThread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;//构造函数,根据参数设置线程优先级
}
/**
* Call back method that can be explicitly over ridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {//主要提供给子类,让子类去重写
}
public void run() {//run方法,终点来了
mTid = Process.myTid();//获取TID
Looper.prepare();//后面在Looper类里看
synchronized (this) {//同步
mLooper = Looper.myLooper();//后面在Looper类里看
notifyAll();//唤醒持有该对象的并且wait的线程
}
Process.setThreadPriority(mPriority);//设置线程优先级
onLooperPrepared();//HandlerThread类里没有实现,子类可以实现,做一些预处理操作
Looper.loop();//后面在Looper类里看
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {//如果线程死掉了,返回null
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {//如果线程活着,但是为null,就一直等待,与run方法里面的synchronized相一致
try {
wait();//当线程没有被start(start之后才会alive)或者没有获取到Looper对象时wait。注意run方法中有notify操作。
} catch (InterruptedException e) {
}
}
}
return mLooper;//返回Looper成员变量
}
/**
* Ask the currently running looper to quit. If the thread has not
* been started or has finished (that is if {@link #getLooper} returns
* null), then false is returned. Otherwise the looper is asked to
* quit and true is returned.
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();//后面在Looper类里看
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {//返回TID
return mTid;
}
}
源代码不是很多,有些涉及到Looper类里面的方法,我们再来看一下Looper类的源代码(只分析涉及到的方法和成员变量)。
/*
* Copyright (C) 2006 The Android Open Source Project
*/
package android.os;
import android.util.Log;
import android.util.Printer;
import android.util.PrefixPrinter;
public class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
private Printer mLogging = null;
private static Looper mMainLooper = null; // guarded by Looper.class
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());//把和当前线程相关的Looer变量(参考Looper构造方法)放进sThreadLocal中
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
Looper me = myLooper();//获取和当前线程相关的Looper变量
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me.mQueue;//和当前线程相关的Looper变量的MessageQueue
// 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();
while (true) {//死循环哟,不过没关系,在MessageQueue中有处理,涉及到wait和notify,可以去MessageQueue中探究。
Message msg = queue.next(); // might block,获取Message
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
msg.target.dispatchMessage(msg);//这一句最关键,Message的Target是什么?没错,是Handler,下面我们就来看一下Handler类
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// 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.recycle();//回收利用Message,所以以后我们使用Message的时候,多使用obtain方法。
}
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
/**
* Return the {@link MessageQueue} object associated with the current
* thread. This must be called from a thread running a Looper, or a
* NullPointerException will be thrown.
*/
public static MessageQueue myQueue() {
return myLooper().mQueue;
}
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
public void quit() {
Message msg = Message.obtain();
// NOTE: By enqueueing directly into the message queue, the
// message is left with a null target. This is how we know it is
// a quit message.
mQueue.enqueueMessage(msg, 0);
}
}
我们来看一下Handler类的源代码
/*
* Copyright (C) 2006 The Android Open Source Project
*/
package android.os;
import android.util.Log;
import android.util.Printer;
import java.lang.reflect.Modifier;
/**
* A Handler allows you to send and process {@link Message} and Runnable
* objects associated with a thread's {@link MessageQueue}. Each Handler
* instance is associated with a single thread and that thread's message
* queue. When you create a new Handler, it is bound to the thread
* message queue of the thread that is creating it -- from that point on,
* it will deliver messages and runnables to that message queue and execute
* them as they come out of the message queue.
* /
public class Handler {
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {//重要,在Lopper.loop()方法里面里调用的就是这个方法
if (msg.callback != null) {
handleCallback(msg);//msg的callBack成员变量是Runnable类型,这里执行的是msg.callback.run(),但是我们一般不给Message的callback成员变量赋值。
} else {
if (mCallback != null) {//如果我们给new()的Handler类的Callback类型的成员变量赋值,就往下面执行,但是我们一般不这么做。
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//我们一般在这做我们想要的操作,这个方法需要我们继承Handler类后重写。
}
}
/**
* Default constructor associates this handler with the queue for the
* current thread.
*
* If there isn't one, this handler won't be able to receive messages.
*/
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> 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 that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
/**
* Constructor associates this handler with the queue for the
* current thread and takes a callback interface in which you can handle
* messages.
*/
public Handler(Callback callback) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> 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 that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
}
public final Message obtainMessage()
{
return Message.obtain(this);//获取msg,最后调用的msg的obtain()方法,最后msg的target就是this,也就是调用者Handler
}
/**
* Use the provided queue instead of the default one.
*/
public Handler(Looper looper) {//MessageQueue怎么关联起来,其实就是在这里关联起来的,通过Handler的构造方法。
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}
/**
* Use the provided queue instead of the default one and take a callback
* interface in which to handle messages.
*/
public Handler(Looper looper, Callback callback) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
}
// if we can get rid of this method, the handler need not remember its loop
// we could instead export a getMessageQueue() method...
public final Looper getLooper() {
return mLooper;
}
private final void handleCallback(Message message) {
message.callback.run();
}
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
IMessenger mMessenger;
}
Looper类和Handler类的源代码不完整,只是分析了和HandlerThread相关的成员变量和方法。
经过我们的一步步分析,现在思路就清晰了:
1. 当HandlerThread运行到Looper.loop()的时候,一直死循环。通过msg.target.dispatchMessage(msg)方法让msg的target(当通过Handler的obtainMessage()系列方法获取msg的时候,msg的target就是该handler)也就是Handler去通过它的handleMessage(msg)方法去处理msg。
2. 但是msg是那里来的?通过看源代码我们发现是通过当前线程的Looper的MessageQueue类型的变量mQueue.next()方法得到的。
3. Handler也有一个MessageQueue类型的变量,那么,Handler的MessageQueue变量怎么和Looper类的MessageQueue类型变量有关系吗?
4. 记不记得Handler类有一个构造方法叫public Handler(Looper) ? 对了,就是这个构造方法让他们产生了关系。( HandlerThread有一个Looper类型的变量,通过getLooper()方法能获取,传入到Handler类的构造方法,这样,Handler就和HandlerThread联系起来了)。
5. 以至于最后HandlerThread操作的是和Handler同一个MessageQueue。
6. Handler可以通过sendMessage(msg)系列方法把msg放到MessageQueue,然后HandlerThread把msg从MessageQueue里面取出来,然后调用Handler的handleMessage(msg)方法处理。
通俗的总结一下运行时的流程:Handler把Message放到MessageQueue,HandlerThread不停的从MessageQueue里拿出来Message,然后调用Handler的HandleMessage(Message)方法不停的处理Message。
经过分析,我们来写一个demo测试一下,有消息队列的线程(非主线程):
工程如下
下面是我测试结果:
结果表示:HandlerThread确实维护了一个消息队列,从Log中可以看出他们的TID都是一样的。
总结:
1. HandlerThread维护了一个消息队列,这样我们不用到处新建对象。
2. Message其实有一套缓冲+循环利用机制,以后用到Message的地方都用obtain()系列方法获取,能节约资源,提高效率。