我们经常这样创建handler,和使用Handler,
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
handler.sendEmptyMessage(0);
但是有的时候这样创建会报错:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
}
}
会报错:
Can't create handler inside thread that has not called Looper.prepare()
这个时候我们可能会在Handler 前后加上Looper.prepare();和 Looper.loop();
到现在,我们还没有切入正题,为什么??我们首先来看一下Handler 的创建会做什么事情:
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());
}
}
<span style="color:#ff0000;">mLooper = Looper.myLooper();</span>
<span style="color:#ff0000;">if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}</span>
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
在这里我们看到一段使用Looper代码的地方,那么Looper 又做了什么呢?我们继续往下看:
/**
* 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();
}
Looper 想要获取于当前线程绑定的 Looper 对象。可是我们自己并没有创建,那是谁给我们创建了,发现在ActivityThread中 已经帮我们初始化:
在Looper中 prepareMainLooper 的方法如下:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
只有调用了prepare() 方法就会创建Looper,但是在主线程中,ActivityThread 初始化的时候已经为我们创建了主线程的 Looper 对象,所以我们在主线程不需要在创建Looper对象了,只需要绑定Handler 对象就可以,所以主线程中可以创建多个Handler对象,同样在子线程中,如果我们需要创建Handler 对象就必须先调用 Looer.prepare()方法创建Looper对象。
以上为创建过程,同样为什么还要调用Looper.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();
<span style="color:#cc0000;">for (;;) </span>{
<span style="color:#cc0000;">Message msg = queue.next(); // might block</span>
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);
}
<span style="color:#cc0000;">msg.target.dispatchMessage(msg);</span>
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();
}
}
我们可以看到loop 方法起始就是一个循环调用队列,获取队列消息,并交给对应的 Handler 去处理消息。它可以保证当前线程不被销毁回收。所以在退出activity时确保消息队列里面没有消息等待处理,可以手动调用Handler.
removeMessages();