有了之前博客的消息机制的介绍,大体知道了各个类的功能。
我们先看HandlerThread,首先它是一个线程
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();//线程id
Looper.prepare();//再来看看prepare函数
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
再来看看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");
}
sThreadLocal.set(new Looper(quitAllowed));//这是一个线程局部变量,也就是每个线程都有一个looper变量
}
来看看它在Lopper类中的定义
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
下面是java文档对这个类的说明:
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
myLopper就是从每个线程中取Looper对象
public static Looper myLooper() {
return sThreadLocal.get();
}
而loop函数,就是循环变量消息队列
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.recycleUnchecked();
}
}
再看Handler,有looper,就把mLooper赋值
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
没有就是用现在线程的looper
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) {
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;
mAsynchronous = async;
}
再看handler里的post类方法:
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
就是将msg的callback设为传进来的参数
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
再看sendMessageAtTime函数
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
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);
}
enqueueMessage函数
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//设置target
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//这个函数就不分析了,就是把msg根据when放到合适的位置
}
最后再loop函数中,会分发消息
msg.target.dispatchMessage(msg);
msg.target是每个handler
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//如果每个消息自己有callback,就自己调用。比如post类函数
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {//用成员变量的回调
return;
}
}
handleMessage(msg);//最后上面都没有就是用handleMessage,但是在Handler类中该函数为空,所以一定要在子类实现。要不消息就没有处理了
}
}
handleCallback函数,用message自己的回调
private static void handleCallback(Message message) {
message.callback.run();
}
最后再来看看一个同步问题:一般会建一个HandlerThread,和一个handler,handler会使用HandlerThread的Looper。
一般代码为:
HandlerThread thread = new HandlerThread();
thread.start();
Handler handler = new Handler(thread.getLooper());//一定要在线程start后去,要不looper为空的。
但是上面的代码线程的start,跑的run函数,和thread.getLooper是在两个线程中的,thread只是一个对象而已,只有run函数才是在另外一个线程中。
这时候线程开启了,而极有可能先调thread.getLooper,但是可能run函数没有跑到mLooper = Looper.myLooper,所以thread.getLooper中的mLooper 为null,这时候加入了wait、notify机制。先让getLooper中wait,这时候也会释放锁,直到run中调notfiyAll,才能把wait唤醒,这时候mLooper也赋值了。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
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()) {//一定要线程开启之后才有值
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;
}