什麼時候需要 Looper
Looper用於封裝了android線程中的訊息迴圈,預設情況下一個線程是不存在訊息迴圈(message loop)的,需要調用Looper.prepare()來給線程建立一個訊息迴圈,調用Looper.loop()來使訊息迴圈起作用,使用Looper.prepare()和Looper.loop()建立了訊息佇列就可以讓訊息處理在該線程中完成。
使用Looper需要注意什麼
寫在Looper.loop()之後的代碼不會被立即執行,當調用後mHandler.getLooper().quit()後,loop才會中止,其後的代碼才能得以運行。Looper對象通過MessageQueue來存放訊息和事件。一個線程只能有一個Looper,對應一個MessageQueue。
比如下面的代碼,只要調用了getLooper().quit()後代碼2才會執行。
class LooperThread extends Thread{4 public void run() {Looper.prepare();//代碼1....Looper.loop();//代碼2....} }
警惕線程未終止造成的記憶體泄露;譬如在Activity中關聯了一個生命週期超過Activity的Thread,在退出Activity時切記結束線程。一個典型的例子就是HandlerThread的run方法是一個死迴圈,它不會自己結束,線程的生命週期超過了Activity生命週期,我們必須手動在Activity的銷毀方法中中調運thread.getLooper().quit();才不會泄露。
Looper與Activity
Activity的MainUI線程預設是有訊息佇列的。所以在Activity中建立Handler時,不需要先調用Looper.prepare()
主線程中的Looper.loop()一直無限迴圈為什麼不會造成ANR
ActivityThread.java 是主線程入口的類,這裡你可以看到寫Java程式中司空見慣的main方法,而main方法正是整個Java程式的入口。
ActivityThread源碼
public static final void main(String[] args) {...//建立Looper和MessageQueueLooper.prepareMainLooper();...//輪詢者開始輪詢Looper.loop();...}
Looper.loop()方法
while (true) {//取出訊息佇列的訊息,可能會阻塞Message msg = queue.next(); // might block...//解析訊息,分發訊息msg.target.dispatchMessage(msg);...}
ActivityThread的main方法主要就是做訊息迴圈,一旦退出訊息迴圈,那麼你的應用也就退出了。那為什麼這個死迴圈不會造成ANR異常呢?
因為Android 的是由事件驅動的,looper.loop() 不斷地接收事件、處理事件,每一個點擊觸摸或者說Activity的生命週期都是運行在 Looper.loop() 的控制之下,如果它停止了,應用也就停止了。只能是某一個訊息或者說對訊息的處理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。也就說我們的代碼其實就是在這個迴圈裡面去執行的,當然不會阻塞了。
handleMessage方法部分源碼
public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case LAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");final ActivityClientRecord r = (ActivityClientRecord) msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);handleLaunchActivity(r, null);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}break;case RELAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");ActivityClientRecord r = (ActivityClientRecord) msg.obj;handleRelaunchActivity(r);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}break;case PAUSE_ACTIVITY:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");handlePauseActivity((IBinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0);maybeSnapshot();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;case PAUSE_ACTIVITY_FINISHING:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");handlePauseActivity((IBinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;...........}}
可以看見Activity的生命週期都是依靠主線程的Looper.loop,當收到不同Message時則採用相應措施。
如果某個訊息處理時間過長,比如你在onCreate(),onResume()裡面處理耗時操作,那麼下一次的訊息比如使用者的點擊事件不能處理了,整個迴圈就會產生卡頓,時間一長就成了ANR。