
在Android開發中主線程扮演著至關重要的角色。毫不夸張的說它就相當于Android的心臟。只要它還在跳動的運行Android應用就不會終止。它負責處理UI事件、界面更新、以及與用戶交互的各種操作。本文將深入分析Android主線程的原理、獨特機制以及應用為開發者提供全面的了解和掌握主線程的知識。主線程的原理Android應用的核心原則之一是單線程模型也就是說大多數與用戶界面相關的操作都必須在主線程中執行。這一原則的背后是Android操作系統的設計主要有以下幾個原因UI一致性在單線程模型下UI操作不會被多線程競爭導致的不一致性問題確保了用戶界面的穩定性和一致性。性能優化單線程模型簡化了線程管理降低了多線程帶來的復雜性有助于提高應用性能。安全性通過將UI操作限制在主線程可以減少因多線程競爭而引發的潛在問題如死鎖和競爭條件。主線程的原理可以用以下偽代碼表示publicclassMainThread{publicstaticvoidmain(String[]args){// 初始化應用Application appcreateApplication();// 創建主線程消息循環Looper.prepareMainLooper();// 啟動主線程while(true){Message msgLooper.getMainLooper().getNextMessage();if(msg!null){// 處理消息app.handleMessage(msg);}}}}在上述偽代碼中主線程通過消息循環Message Loop來不斷處理消息這些消息通常包括UI事件、定時任務等。應用的UI操作都會被封裝成消息然后由主線程依次處理。主線程的獨特機制主線程有一些獨特的機制其中最重要的是消息隊列Message Queue和Handler。消息隊列Message Queue消息隊列是主線程用來存儲待處理消息的數據結構。每個消息都有一個與之相關的Handler它負責將消息放入隊列中然后由主線程依次處理。消息隊列的機制確保了消息的有序性和及時性。publicMessagenext(){final long ptrmPtr;if(ptr0){returnnull;}int pendingIdleHandlerCount-1;int nextPollTimeoutMillis0;for(;;){if(nextPollTimeoutMillis!0){Binder.flushPendingCommands();}nativePollOnce(ptr,nextPollTimeoutMillis);synchronized(this){final long nowSystemClock.uptimeMillis();Message prevMsgnull;Message msgmMessages;if(msg!nullmsg.targetnull){do{prevMsgmsg;msgmsg.next;}while(msg!null!msg.isAsynchronous());}if(msg!null){if(nowmsg.when){nextPollTimeoutMillis(int)Math.min(msg.when-now,Integer.MAX_VALUE);}else{// Got a message.mBlockedfalse;if(prevMsg!null){prevMsg.nextmsg.next;}else{mMessagesmsg.next;}msg.nextnull;msg.markInUse();returnmsg;}}else{nextPollTimeoutMillis-1;}...}...}}HandlerHandler是一個與特定線程關聯的對象它可以用來發送和處理消息。在主線程中通常使用new Handler(Looper.getMainLooper())來創建一個與主線程關聯的Handler。開發者可以使用Handler來將任務提交到主線程的消息隊列中。Handler handlernewHandler(Looper.getMainLooper());handler.post(newRunnable(){Overridepublicvoidrun(){// 在主線程執行}});同步屏障在Android中消息可以分為同步消息和異步消息。通常我們發送的消息都是同步消息。然而有一種特殊情況即開啟同步屏障。同步屏障是一種消息機制的特性可以阻止同步消息的處理只允許異步消息通過。通過調用MessageQueue的postSyncBarrier()方法可以開啟同步屏障。在開啟同步屏障后發送的這條消息它的target為null。privateintpostSyncBarrier(long when){synchronized(this){final int tokenmNextBarrierToken;final Message msgMessage.obtain();msg.markInUse();// 沒有設置targettarget為nullmsg.whenwhen;msg.arg1token;Message prevnull;Message pmMessages;if(when!0){while(p!nullp.whenwhen){prevp;pp.next;}}if(prev!null){// invariant: p prev.nextmsg.nextp;prev.nextmsg;}else{msg.nextp;mMessagesmsg;}returntoken;}}那么開啟同步屏障后所謂的異步消息又是如何被處理的呢我們又可以回到之前MessageQueue中的next方法了publicMessagenext(){// 省略部分代碼只體現出來同步屏障的代碼...for(;;){...synchronized(this){final long nowSystemClock.uptimeMillis();Message prevMsgnull;Message msgmMessages;//注意這里開始出來同步屏障//如果targetnull認為它就是屏障進行循環遍歷直到找到第一個異步的消息if(msg!nullmsg.targetnull){do{prevMsgmsg;msgmsg.next;}while(msg!null!msg.isAsynchronous());}...}...}}所以同步屏障是會讓消息順序進行調整讓其忽略現有的同步消息來直接處理臨近的異步消息。現在聽起來已經知道了同步屏障的作用但它的實際應用又有哪些呢應用場景雖然在日常應用開發中同步屏障的使用頻率較低但在Android系統源碼中同步屏障的使用場景非常重要。一個典型的使用場景是在UI更新時例如在View的繪制、布局調整、刷新等操作中系統會開啟同步屏障以確保與UI相關的異步消息得到優先處理。當UI更新完成后同步屏障會被移除允許后續的同步消息得以處理。對應的是ViewRootImpl#scheduleTraversals()voidscheduleTraversals(){if(!mTraversalScheduled){mTraversalScheduledtrue;// 設置同步屏障mTraversalBarriermHandler.getLooper().getQueue().postSyncBarrier();mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,mTraversalRunnable,null);notifyRendererOfFramePending();pokeDrawLockIfNeeded();}}voidunscheduleTraversals(){if(mTraversalScheduled){mTraversalScheduledfalse;// 移除同步屏障mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);mChoreographer.removeCallbacks(Choreographer.CALLBACK_TRAVERSAL,mTraversalRunnable,null);}}經典問題Android 主線程的消息循環是通過Looper和Handler來實現的。以下是一段偽代碼示例// 創建一個 Looper關聯當前線程Looper.prepare();Looper loopLooper.myLooper();// 創建一個 Handler它將和當前 Looper 關聯Handler handlernewHandler();// 進入消息循環Looper.loop();開啟loop后的核心代碼如下publicstaticvoidloop(){final Looper memyLooper();...for(;;){if(!loopOnce(me,ident,thresholdOverride)){return;}}}privatestaticbooleanloopOnce(final Looper me,final long ident,final int thresholdOverride){// 注意沒消息會被阻塞進入休眠狀態Message msgme.mQueue.next();// might blockif(msgnull){// No message indicates that the message queue is quitting.returnfalse;}...try{msg.target.dispatchMessage(msg);if(observer!null){observer.messageDispatched(token,msg);}dispatchEndneedEndTime?SystemClock.uptimeMillis():0;}catch(Exception exception){if(observer!null){observer.dispatchingThrewException(token,msg,exception);}throwexception;}finally{ThreadLocalWorkSource.restore(origWorkSource);if(traceTag!0){Trace.traceEnd(traceTag);}}...msg.recycleUnchecked();returntrue;}在這段示例中主線程的消息循環被啟動它會等待來自消息隊列的消息。有了這個基礎下面的問題就簡單了為什么主線程不會陷入無限循環主線程的消息循環不會陷入無限循環因為它不斷地從消息隊列中獲取消息并處理它們。如果沒有消息要處理消息循環會進入休眠狀態不會持續消耗 CPU 資源。只有在有新消息到達時主線程才會被喚醒來處理這些消息。這個機制確保主線程能夠響應用戶的操作而不陷入死循環。如果沒有消息主線程會如何處理如果消息隊列為空主線程的消息循環會等待直到有新消息到達。在等待期間它不會執行任何操作也不會陷入循環。這是因為 Android 的消息循環是基于事件驅動的只有當有事件消息到達時才會觸發主線程執行相應的處理代碼。當新消息被投遞到消息隊列后主線程會被喚醒執行相應的處理操作然后再次進入等待狀態。這種事件驅動的消息循環機制使得 Android 應用能夠高效地管理用戶交互和異步操作同時保持了響應性和低能耗。所以主線程不會陷入無限循環而是在需要處理事件時才會執行相應的代碼。結論Android主線程是應用的核心負責處理UI事件、界面更新和定時任務等。了解主線程的原理和獨特機制是Android開發的關鍵它有助于確保應用的穩定性和性能。通過消息隊列和Handler開發者可以在主線程中安全地處理各種任務提供流暢的用戶體驗。最后大家分享一份全套的Android學習資料給那些想學習 Android 的小伙伴們一點幫助適用于任何想學習Android開發但不知道從哪里開始的人也適用于已經開始進行Android開發但想要變得更好的任何人一、Android所有方向的學習路線為了成為更好的 Android 開發者這里為大家提供了總的路線圖。它的用處就在于你可以按照上面的知識點去找對應的學習資源保證自己學得較為全面。如果下面這個學習路線能幫助大家成為一個更好的 Android 開發者那么我的使命也就完成了包括Android應用開發、系統開發、音視頻開發、Flutter開發、小程序開發、UI界面、車載系統開發等等二、學習軟件工欲善其事必先利其器。學習Android常用的Android Studio視頻教程和Android Studio最新的安裝包都在這里了給大家節省了很多時間。三、進階學習視頻我們在學習的時候往往書籍源碼難以理解閱讀困難這時候視頻教程教程是就很適合了生動形象加上案例實戰科學有趣才能更方便的學習下去。四、實戰案例光學理論是沒用的要學會跟著一起敲要動手實操才能將自己的所學運用到實際當中去這時候可以搞點實戰案例來學習。五、經典書籍閱讀閱讀Android經典書籍可以幫助讀者提高技術水平開拓視野掌握核心技術提高解決問題的能力同時也可以借鑒他人的經驗。對于想要深入學習Android開發的讀者來說閱讀Android經典書籍是非常有必要的。六、面試資料我們學習Android必然是為了找到高薪的工作下面這些面試題是來自阿里、騰訊、字節等一線互聯網大廠最新的面試資料并且有阿里大佬給出了權威的解答刷完這一套面試資料相信大家都能找到滿意的工作。這份完整版的Android全套學習資料已經上傳CSDN朋友們如果需要可以微信掃描下方CSDN官方認證二維碼免費領取【保證100%免費】