1. 程式人生 > >為什麼在主執行緒的Looper.looper死迴圈不會卡死

為什麼在主執行緒的Looper.looper死迴圈不會卡死

public static void main(String[] args) { 
.... //建立Looper和MessageQueue物件,用於處理主執行緒的訊息 
Looper.prepareMainLooper();
 //建立ActivityThread物件 
//建立Binder通道 (建立新執行緒) 
thread.attach(false); Looper.loop(); //訊息迴圈執行 
throw new RuntimeException("Main thread loop unexpectedly exited");
 }

我們看looper.loop()的原始碼


    /** 
         * Run the message queue in this thread. Be sure to call 
         * {@link #quit()} to end the loop. 
         */
public static void loop() { Looper me = myLooper();//獲取當前looper if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); }//如果為空,則拋異常 MessageQueue queue = me.mQueue;//把當前looper的queue賦值給區域性變數queue
// 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();//確保當前執行緒屬於當前程序,並且記錄真實的token。 final long ident = Binder.clearCallingIdentity(); while
(true) { Message msg = queue.next(); // might block有可能會阻塞 if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message.退出訊息的標示就是target為空 return; } long wallStart = 0; long threadStart = 0; // This must be in a local variable, in case a UI event sets the logger 一個區域性變數,為ui事件設定log記錄。 Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); wallStart = SystemClock.currentTimeMicro(); threadStart = SystemClock.currentThreadTimeMicro(); } //handler處理訊息 msg.target.dispatchMessage(msg); if (logging != null) { long wallTime = SystemClock.currentTimeMicro() - wallStart; long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); if (logging instanceof Profiler) { ((Profiler) logging).profile(msg, wallStart, wallTime, threadStart, threadTime); } } // 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); } //處理完成後,呼叫Message.recycle()將其放入Message Pool中。 msg.recycle(); } } }

那麼知乎上一個大神這麼說 隔開隔開

對於執行緒既然是一段可執行的程式碼,當可執行程式碼執行完成後,執行緒生命週期便該終止了,執行緒退出。而對於主執行緒,我們是絕不希望會被執行一段時間,自己就退出,那麼如何保證能一直存活呢?簡單做法就是可執行程式碼是能一直執行下去的,死迴圈便能保證不會被退出,例如,binder執行緒也是採用死迴圈的方法,通過迴圈方式不同與Binder驅動進行讀寫操作,當然並非簡單地死迴圈,無訊息時會休眠。但這裡可能又引發了另一個問題,既然是死迴圈又如何去處理其他事務呢?通過建立新執行緒的方式。
真正會卡死主執行緒的操作是在回撥方法onCreate/onStart/onResume等操作時間過長,會導致掉幀,甚至發生ANR,looper.loop本身不會導致應用卡死。

隔開隔開
這是一個大神說的 乍看起來好像有點不懂
那麼我來說說我的理解
Looper.loop()中的for迴圈會讓當前執行緒阻塞,不是卡死,這個和作業系統有關。如果你在主執行緒操作,如activity生命週期onCreate、主執行緒的handler,實際上是都是通過handler發訊息的,訊息會在剛才的for迴圈中處理,這個訊息會喚醒執行緒,如果你在onCreate(),onResume()裡面處理耗時操作,那麼下一次的比如使用者的點選事件不能處理了,那就會卡死了