編輯:關於android開發
什麼時候需要 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。
Android UI:ListView,androiduilistviewSimpleAdapter是擴展性最好的適配器,可以定義各種你想要的布局,而且使用很方便。 l
Intent(三)向下一個活動傳遞數據,intent傳遞 向下傳遞活動很簡單,可以我采用putExtra()方法的重載,把
如何取得nginx做反向代理時的真實IP?nginx做反向代理時的真實IP.pdf1.編譯對於client->nginxreverseproxy->apach
關於android百度地圖sdk的配置常見問題,androidsdk1,模擬機上在創建地圖的xml的時候不能創建<MapView>,需要創建<Textu