Handler是Android中的消息處理機制,多用于線程之間傳遞消息。
一.使用方法
final Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.v(TAG,"handleMessage is running:"+msg.what);
}
};
new Thread(){
@Override
public void run() {
super.run();
Log.v(TAG, "new a Thread");
for(int i = ; i < ;i ++){
mHandler.sendEmptyMessage(i);
}
}
}.start();
或者
Runnable mRunnable = new Thread(){
@Override
public void run() {
super.run();
Log.v(TAG, "new a Thread:");
for(int i = ; i < ;i ++){
mHandler.sendEmptyMessage(i);
}
}
};
new Handler().post(mRunnable);
使用Handler 存在的問題
記憶體方面
Handler 被作為 Activity 引用,如果為非靜态内部類,則會引用外部類對象。當 Activity finish 時,Handler可能并未執行完,進而引起 Activity 的記憶體洩漏。故而在所有調用 Handler 的地方,都用靜态内部類。
異常方面
當 Activity finish 時,在 onDestroy 方法中釋放了一些資源。此時 Handler 執行到 handlerMessage 方法,但相關資源已經被釋放,進而引起空指針的異常。為解決這個問題,如果是使用 handlerMessage,則在方法中加try catch。如果是用 post 方法,則在Runnable方法中加try catch。
二. Looper,MessageQueue,Hanlder
MessageQueue: 消息隊列,把加入的Message消息互相連結起來組成一個單連結清單。
Handler:負責把Message消息加入MessageQueue隊列中
Looper:負責循環讀取MessageQueue消息隊列中的消息,并把消息派發給相應的類處理(Handler,Runnable )
ActivityThread:
public static void main(String[] args) {
......
Looper.prepareMainLooper();//為UI線程設定Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();//循環讀取MessageQueue隊列,取出Message做處理
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper
public final class Looper {
//靜态
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//建構Looper對象
public static void prepare() {
prepare(true);
}
//建構Looper對象,并把新建構的Looper對象儲存到sThreadLocal 中
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));
}
//建構UI線程的Looper對象
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//循環讀取MessageQueue隊列,取出Message并回調msg.target.dispatchMessage(msg)。target就是Handler對象的引用
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();
//死循環讀取MessageQueue并取出Message
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
try {
msg.target.dispatchMessage(msg);//回調Handler中的dispatchMessage()函數
end = (slowDispatchThresholdMs == ) ? : SystemClock.uptimeMillis();
} finally {
if (traceTag != ) {
Trace.traceEnd(traceTag);
}
}
.......
}
}
//取出儲存在sThreadLocal中的Looper對象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
MessageQueue
public final class MessageQueue {
......
//Message加入隊列的操作
boolean enqueueMessage(Message msg, long when) {......}
......
}
Handler
public class Handler {
//如果Message中的callback為空,調用handleCallback(),否則調用handleMessage()
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//回調callback中的run()方法,一般都是Runnable中的run()
private static void handleCallback(Message message) {
message.callback.run();
}
//把Message消息加入到隊列中
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
關于Looper:
每個線程都綁定一個唯一Looper,不能建構多個。如果新建構的線程沒有綁定新的Looper,那這個線程不能使用Handler,否則會報java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()錯誤。我們需要調用prepare()建立Looper對象,并循環取出MessageQueue中的資料,Looper.java源碼中的案例如下:
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>