为了方便在一个新线程中处理消息,android提供了HandlerThread,
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.
其使用步骤如下,假设有两个线程,一个主线程A(Handler所在线程),另外一个Looper所在线程B,
1.主线程A中新建一个HandlerThread,然后调用start()启动新线程B
HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
wmHandlerThread.start();
public class HandlerThread extends Thread {
//新线程B创建的Looper,由于Looper是在static ThreadLocal保存,首先static相当于
//进程中的全局变量,所有线程共享(相同),但是ThreadLocal相当于每个线程有自己独一无二
//的一份Looper(不同),可以利用mLooper = Looper.myLooper()获取
//mLooper非private,线程A可以获取
Looper mLooper;
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
//新线程B开始循环
Looper.loop();
mTid = -1;
}
}
2.主线程A新建一个Handler ,然后可以通过这个Handler组装消息,在线程A中将消息发送到Looper所在的线程B中处理,
//Handler的构造函数可以无参,此时必须保证所在线程Looper已经建立
//构造函数还可以输入其他线程的Looper,这样消息会在Looper所在线程处理
Handler wmHandler = new Handler(wmHandlerThread.getLooper());
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
3.线程A通过Handler发送消息,例如通过Handler.obtainMessage先组装一个Message,
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
其中,消息中的target为本身,即线程A中的wmHandler对象。
public static Message obtain(Handler h, int what, Object obj) {
Message m = obtain();
//这里的target为线程A中的wmHandler对象
m.target = h;
m.what = what;
m.obj = obj;
return m;
}
在java中,所有实例域、静态域和数组元素保存在堆内存,堆内存在线程之间共享,所以在Looper所在线程B中依然可以访问m.target,即wmHandler,相当于在Looper所在线程B利用线程A中提供的方法去处理消息,实际的处理过程是在线程B中。
4.Looper处理消息
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 (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// 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);
}
//循环处理消息
msg.target.dispatchMessage(msg);
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.recycle();
}
}
其中,最主要的就是msg.target.dispatchMessage(msg),获取msg中的target,也就是线程A中的wmHandler对象的dispatchMessage函数。从dispatchMessage函数可以看出,可以通过以下三种方法处理消息:
如果定义了msg的callback,会去利用msg.callback处理Message;
如果在构造Handler时,定义了mCallback,会去利用mCallback.handleMessage处理Message;
否则通过继承Handler,重写handleMessage函数去处理Message,一般这个方法最普遍。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}