首先先看一下android中的线程基本使用方式:
1. 继承Thread方式:复写run()方法
2. 实现Runnable方式 接口:传给Thread : new Thread(newplaybackRunnable()).start();
以上两种方法殊归同途,都是在新线程中调用用户实现run方法(方式上还是有区别的,需要可以查看资料,在我的搜藏中也有)。
下面我们来关注下android中的hanlder机制。handler主要的用途就是提供一个消息机制,可以方便地在一个消息循环线程中实现消息的处理,无论是在本线程还是在其他线程。不过,首先需要保证线程是有消息循环的。android中的UI线程都是由消息循环的。
来看一下handler机制三个相关的类:Handler, Message, Looper
首先来看下Looper类:它的构造函数是私有的,可见不能在外部创建。唯一创建的地方:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
thrownewRuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
此处创建了,就把它设置到ThreadLocal中。
再来看看Looper构造函数都干了什么:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
它创建了一个消息队列,又结合上面的prepare函数,可见Looper实例在一个Thread中使唯一的,进而消息队列也是唯一的。
然后是loop的主循环体:它不停地从消息队列中取出消息来处理。
public static void loop() {
final Looper me = myLooper();
//note how find the Looper
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();
}
}
这里注意消息队列的获得,来看mylooper函数:
public static Looper myLooper() {
return sThreadLocal.get();
}
可见,要想消息循环,之前必须要构造出looper实例,并放入到ThreadLocal中。这里,looper已经处理好了,是要调用上面的prepare函数,切忌!
然后就是消息如何处理了,可以看到,最主要的就是msg.target.dispatchMessage(msg);这句话,这句就会使你的消息调用handler的dispatchMessage(msg)函数来处理消息了:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
从上就看到了处理消息的三种方式:
1. 调用消息的callback
2. 调用Hanlder的callback
3. 调用handler的handleMessage
再来看看Handler:
Handler总体来说有两种构造方式:
1. 不带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;
}
}
2. 带looper的构造方式:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
不带looper的构造方式将获得本线程的Queue, 带looper的构造方式,获得的是looper的Queue.这为之后handler跑在哪个线程上打上了伏笔。
最后看看Message:
Message的构造大体分为三种:
1. 不带handler和callback的构造:
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
此时target为null
2. 带参数Handler的构造:
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
此时target为传入的handler
3. 带handler和callback的构造:
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
有了以上这些基础,我们再来看看消息handler机制是如何使用的:
有几种方式:
1. 直接获取message,然后传给handler处理:
Msg = Message.obtain();
Handler.sendMessage(msg);
这里可以跟踪Handler.sendMessage(msg),最后走到:
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);
}
可以看到,以上将msg入队到自己的queue中,最后就到了queue的线程中去处理了:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
注意这里msg.target = this; 所以无论消息有没有设置target,只要调用了Handler的SendMessage, 它的处理就绑定到了handler上了。
Ok ! 这种方式是跑在handler的线程中的,至于handler值跑在哪个线程中,看看上面handler的两种构造函数就知道了。
2. 通过hanlder来获得Message:
class Handler{
public final Message obtainMessage()
{
return Message.obtain(this);
}
}
可见最后调用的还是消息的obtain(Hanlder)函数。还是在handler的handleMessage中处理。
3. 通过handler的post方式:
Handler. post(Runnable r):
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
最后还是在handler的线程中,处理的是runnable接口的实现。
4. 通过message的SendToTarget的方式:
Message.sendToTarget():
public void sendToTarget() {
target.sendMessage(this);
}
可见 这个是在与message关联的handler中处理的。注:处理之前message一定要有与之关联的target(Hanlder),也就是message的获得一定通过有handler的方式获得,或者之后要手动设置下handler,不然会因为找不到target而出错。
好了,以上4种大概就是我们一般使用handler消息机制的一般方式。
总结:
1. Looper不用用户操心,但是构造消息循环线程的话,一定要Looper.prepare()一下,以用来创建本地消息队列。
2. handler的两种构造方式决定了handler是在哪个线程上被处理的。 这里要注意:如果hanlder在本地线程上处理,则本地线程一定要有handler机制,也就是消息循环系统。不然handler会因为找不到Looper而出错!
3. Message的获取方式决定了消息的处理是在哪个函数中进行的(参考上面dispatchmessage处理)。 为消息的处理提供了多种方便的方式(参考Message的构造方式一节)。
最后来看下HandlerThread:
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
这个类为我们提供了一个消息循环线程的所有工作,我们只要在这个线程上处理消息就可以了。
调用此类的getLooper可以得到looper,然后用它来构造hanlder就可以发送消息到这个线程来处理了。