天天看點

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才會執行。

1 class LooperThread extends Thread
 2 {
 3     4     public void run() 
 5     {
 6         Looper.prepare();
 7          //代碼1....
 8         Looper.loop();
 9         //代碼2....
10     }    
11 }              

警惕線程未終止造成的記憶體洩露;譬如在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源碼

1 public static final void main(String[] args) {
2         ...
3         //建立Looper和MessageQueue
4         Looper.prepareMainLooper();
5         ...
6         //輪詢器開始輪詢
7         Looper.loop();
8         ...
9     }      

Looper.loop()方法

1  while (true) {
2        //取出消息隊列的消息,可能會阻塞
3        Message msg = queue.next(); // might block
4        ...
5        //解析消息,分發消息
6        msg.target.dispatchMessage(msg);
7        ...
8     }      

ActivityThread的main方法主要就是做消息循環,一旦退出消息循環,那麼你的應用也就退出了。那為什麼這個死循環不會造成ANR異常呢?

因為Android 的是由事件驅動的,looper.loop() 不斷地接收事件、處理事件,每一個點選觸摸或者說Activity的生命周期都是運作在 Looper.loop() 的控制之下,如果它停止了,應用也就停止了。隻能是某一個消息或者說對消息的處理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。也就說我們的代碼其實就是在這個循環裡面去執行的,當然不會阻塞了。

handleMessage方法部分源碼

1 public void handleMessage(Message msg) {
 2         if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
 3         switch (msg.what) {
 4             case LAUNCH_ACTIVITY: {
 5                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
 6                 final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
 7                 r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
 8                 handleLaunchActivity(r, null);
 9                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
10             }
11             break;
12             case RELAUNCH_ACTIVITY: {
13                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
14                 ActivityClientRecord r = (ActivityClientRecord) msg.obj;
15                 handleRelaunchActivity(r);
16                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
17             }
18             break;
19             case PAUSE_ACTIVITY:
20                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
21                 handlePauseActivity((IBinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0);
22                 maybeSnapshot();
23                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
24                 break;
25             case PAUSE_ACTIVITY_FINISHING:
26                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
27                 handlePauseActivity((IBinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0);
28                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
29                 break;
30             ...........
31         }
32     }      

可以看見Activity的生命周期都是依靠主線程的Looper.loop,當收到不同Message時則采用相應措施。

如果某個消息處理時間過長,比如你在onCreate(),onResume()裡面處理耗時操作,那麼下一次的消息比如使用者的點選事件不能處理了,整個循環就會産生卡頓,時間一長就成了ANR。

總結

  Looper: 每個線程隻有一個Looper,負責管理MessageQueue,會不斷地從MessageQueue中取出消息,并将消息分給對應的Handler處理。

  MessageQueue:由Looper負責管理,采用先進先出的方式管理Message(消息隊列)。

  Handler:把消息發送給Looper管理的MessageQueue并負責處理Looper分給它的消息。

  消息隻能在某個具體的Looper上消耗,是以每個Handler都會綁定一個Looper。但是多個Handler可以綁定同一個Looper(這也是在主線程中能夠建立新的Handler的原因)。

Looper

引用:http://www.jianshu.com/p/cfe50b8b0a41