爲什麼在主線程的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本身不會導致應用卡死。

作者:Gityuan
鏈接:https://www.zhihu.com/question/34652589/answer/90344494
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

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

發佈了35 篇原創文章 · 獲贊 9 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章