
從2022年5月中旬開始我一邊在職一邊準備Android面試白天寫業務晚上刷八股文。那段時間我把網上能翻到的Android面試題、大廠面經、源碼解析筆記幾乎都過了一遍最后沉淀出一份自己的答題套路。現在整理出來說說我在準備Android面試八股文這件事上到底在看什么、背什么、怎么答。先說一個很多人沒想明白的問題八股文為什么值得認真準備因為面試官問你的很多題目表面是考背書能力實際是考你有沒有真正理解這套系統是怎么轉起來的。Handler、Binder、AMS、事件分發、四大組件、ANR、內存泄漏這些2022年依然是Android面試的硬通貨無論你簡歷上寫的是業務開發還是性能優化方向第一輪技術面大概率就是圍繞這些東西展開。你連消息機制都講不清楚后面聊項目、聊架構、聊協程面試官很難信服你的基礎扎實。我這篇八股文篇不是把網上所有題都抄一遍而是按我自己復習時的思路重新拆了一遍哪些是必背的哪些是面試官大概率會追著往下問的哪些是答完一句原理之后還能展開加分的內容。如果你離面試還有一兩周建議先按后面的節奏來。1. 為什么2022年7月我還在啃八股文環境判斷與復習節奏1.1 這個時間節點面試風向2022年年中的Android面試和兩年前相比明顯變了幾個方向。第一Kotlin已經完全是主流Co我們寫新項目基本全Kotlin面試時候Java經常只被用來問基礎但協程、Flow、Compose這些新潮內容才是加分點。第二大廠對源碼級理解的要求更高了光會說Handler用于線程間通信已經不夠面試官會追問Looper在子線程怎么創建、MessageQueue怎么阻塞、為什么不會卡死主線程。第三項目經歷之外的軟技能和思考深度被提到了很高的權重。所以八股文不再只是死記硬背而是要把知識點串成一條完整的鏈路。比如問Activity啟動流程你能不能從Launcher的startActivity一直講到AMS、zygote、ApplicationThread、ActivityThread這整條線。你需要給面試官一種我讀過源碼我懂系統的調用鏈的感覺而不是碎片化地背幾個名詞。1.2 我的復習資料與節奏安排我當時給自己定了兩周的沖刺計劃資料其實很固定《Android開發藝術探索》和《深入理解Android內核設計思想》翻重點章節尤其是消息機制、View體系、Binder這幾塊。網上能找到的大廠面經合集只看近半年內的因為有些問題每年會換花樣。自己項目里真實踩過的坑每個坑都往源碼層面挖一層作為項目里體現基礎的素材。刷題不要貪多我每天只過三個大類系統機制類、View體系類、性能優化類。時間分配上我會用周末兩天把所有核心知識點做成一個腦圖工作日晚上每天攻克一個主題。比如周一看Handler周二看Binder周三看AMS周四看View周五看性能。周六把這一周的問題過一遍周日整理成自己的答題話術。2. Handler、Binder、AMS這三個機制幾乎決定了面試的下限2.1 Handler消息機制從主線程Looper到同步屏障面試官問Handler最常見的開場是你講講Handler機制。很多人會順口說主線程有LooperLooper從MessageQueue里取消息Handler調用handleMessage處理。這句話沒有錯但只能拿到基礎分。真正加分的回答應該是先指出Looper是ThreadLocal存儲的每個線程只有一個Looper、只有一個MessageQueue。然后說主線程的Looper是在ActivityThread.main方法里通過Looper.prepareMainLooper()創建的它不會退出。接著講Handler的sendMessage最終會調用enqueueMessage把Message放到MessageQueue插入的時候按when字段做時間排序不是按投遞順序。面試官這時候往往會追一句MessageQueue沒消息的時候主線程在干什么這里才是關鍵。MessageQueue的next方法是阻塞的它調用nativePollOnce進入epoll機制的等待讓主線程休眠不占用CPU等有消息進來或者有binder事件的時候通過管道/eventfd喚醒。很多只背理論的人會卡在這一步能把native層這一句講出來面試官會覺得你真看過源碼。還有一個容易被追問的點是同步屏障SyncBarrier。正常Message是一串同步消息有需要時可以往MessageQueue插入一個target為null的Message作為同步屏障這個屏障后面的同步消息就不會被執行只能執行異步消息。View的Choreographer在doFrame時插入VSYNC消息就用了這個機制。2022年這里有個變種問法Android 12/13之后引入了異步消息以及暢行等等面試官會問你有沒有細致研究過主線程消息優先級你提一下SyncBarrier就夠了。2.2 Binder面試題一次拷貝到底省了什么Binder是Android面試里最容易答飛的一個點。常見問題就是Android為什么用Binder做跨進程通信而不用共享內存、Socket、管道先記住結論性話術Binder基于C/S架構發送方調用一次copy_from_user把數據從用戶空間拷貝到內核空間接收方通過mmap映射直接把內核空間那同一份內存映射到自己的用戶空間所以是一次拷貝。傳統管道、Socket至少需要兩次拷貝。然后準備一個類比一次拷貝就像你寄快遞快遞員先到你家里把包裹拿走放到了中轉站收件人直接拿著鑰匙開中轉站的門把包裹拿走中間不需要再有人把包裹送到收件人手里。而這個中轉站就是內核對同一塊物理內存的映射。Binder面試還會考幾個延伸點Binder線程池是怎么工作的每個進程啟動時會創建一個Binder線程池默認上限是16個Binder線程執行handleMessage等事務。Binder驅動在哪個文件核心在kernel層你只要說binder.c 即可。四大組件跨進程通信哪些用了BinderAMS、PMS、WMS都是系統服務Android 10之后一些系統服務改用AIDL。Binder的死亡代理linkToDeath。oneway和非oneway的呼叫區別這個很多人在項目中用過AIDL但沒細想。我復習Binder時最大的體會是不要光背一次拷貝要理解mmap為什么能省一次拷貝。因為接收方通過mmap把內核緩沖區直接映射到用戶態發送方復制到內核緩沖區的數據接收方不用再復制一遍直接讀取即可。2.3 Activity啟動流程把AMS拉進回答里Activity啟動流程在2022年依然是高頻題而且面試官普遍希望你在回答中自然冒出AMS、ActivityTaskManager、Zygote、ApplicationThread這些角色。一個標準的回答骨架是這樣Launcher進程調用startActivityActivityManagerShellCommand或者Instrumentation會通過ATMS得到Binder代理。真正執行的是AMS.startActivity再由ActivityTaskManager內部處理任務棧。AMS先檢查進程是否存在不存在就通過Socket請求Zygote fork新進程。Zygote fork出的新進程啟動ActivityThread調用main方法然后scheduleLaunchActivity回到AMS說我準備好了。最后通過ApplicationThread把LaunchActivity的消息發回主線程ActivityThread的handleLaunchActivity執行真正的生命周期回調。這個流程里有一個很刁鉆的追問onCreate、onResume與AMS回調的時序是發生在什么階段你要是說onCreate在attach之后調用那是對的但你得說清楚AMS只是負責狀態管理和調度真正的生命周期執行是由ActivityThread在主線程里完成的。還有一道常考的衍生題一個App冷啟動的完整過程涉及了哪些系統服務答案是Zygote、SystemServer、AMS/PMS、ActivityThread、Application還有Launcher。每一個都可以展開說至少一分鐘這就是八股文的厲害之處一環套一環。3. View體系問答事件分發與繪制流程的五連問3.1 事件分發三兄弟和U型管道View事件分發是我個人覺得最像考駕照扣分細則的一個知識點細節很多但一旦理解了下發和回溯的U型管道整個邏輯就順了。先默寫三個方法的職責dispatchTouchEvent事件分配入口返回true表示事件被消費。onInterceptTouchEventViewGroup專屬是否攔截該事件。onTouchEvent自身是否消費事件。從ACTION_DOWN開始事件從RootView往下傳到手指所在的View如果中間某個ViewGroup的onInterceptTouchEvent返回true事件就被它攔下來交給它的onTouchEvent。如果一路沒人攔截到了目標View它的onTouchEvent如果返回false事件會沿著父容器一層層回溯直到有人消費。這就是經典的U型管道。面試官喜歡挖的細節有三個同一個事件序列中ACTION_DOWN與ACTION_MOVE的關系如果DOWN沒人消費這一整個序列都不會再傳過來如果MOVE被攔截子View會收到ACTION_CANCEL。requestDisallowInterceptTouchEvent(CANCEL)寫在子View里可以禁止父容器攔截。事件分發和點擊事件的onClick怎么串起來onTouchEvent里有個performClick的調用點但只有先消費了DOWN和UP且事件沒有被打斷才會觸發performClick。我建議復習時用一張腦圖把dispatchTouchEvent的返回值畫出來因為面試時能準確說出DOWN返回trueMOVE繼續分發給同一目標如果MOVE返回false但DOWN是true最終會照樣消費掉這種細節的人其實是少數。3.2 繪制流程measure、layout、draw的邊界和觸發條件繪制流程的八股經常和自定義View一起考。面試官會問自定義View的onMeasure為什么要小心或者layout和draw的觸發時機是什么我整理的答題順序是開頭先說入口ViewRootImpl.performTraversals里面依次調用performMeasure、performLayout、performDraw。然后說MeasureSpec的三種模式EXACTLY確定尺寸、AT_MOST最大限制、UNSPECIFIED無限制。接著說MeasureSpec的值是由父View的MeasureSpec和自身的LayoutParams通過getChildMeasureSpec計算出來的。最后說layout階段確定View的位置draw階段通過Canvas繪制背景、內容、子View、裝飾。最容易踩的坑是onMeasure里不遵守SpecMode。比如ListView/RecyclerView的item高度被設為wrap_content時如果不處理AT_MOST模式會造成item復用錯亂或者顯示異常。實踐里我在onMeasure里拿到AT_MOST模式時會計算最小高度保證邏輯合理這個細節可以作為面試答題時的一個亮點。關于invalidate和requestLayout的區別也是必問invalidate會執行draw但不會relayoutrequestLayout會重新measurelayoutdraw一般用于尺寸變化。頻繁調requestLayout容易掉幀這也能串到性能優化上。3.3 自定義View衍生題onMeasure的防坑點2022年面試問自定義View已經不滿足于你畫過一個圓了。面試官會拿出一套組合拳如果View的寬高不指定會顯示多大 答案是0。你必須自己在onDraw里處理Drawable的自然寬高或者在measure時讓模pact。onDraw里能不能做耗時操作 不能因為主線程繪制超過16ms就會掉幀。為什么RecyclerView滑出屏幕的item會復用 因為ViewHolder機制但如果你用wrap_content且onMeasure有問題復用會出現顯示錯亂。如果在onDraw里postInvalidate會怎樣 會變成每幀都重新繪制性能暴雷。這些衍生題其實考察的還是你對measure和draw的理解是否透徹。所以我復習時把自定義View分成兩條線一條線要求自己畫一個圓形進度條并說清onMeasure里如何支持wrap_content另一條線要求自己說清requestLayout的調用鏈也就是ViewRootImpl.performTraverse如何被觸發。每一條線都準備2分鐘左右的口頭講解面試時再臨場演繹。4. 性能優化追問鏈ANR、內存泄漏與卡頓的底層邏輯4.1 ANR你以為的5秒其實不是全部ANR的八股題標準答案是Input事件5秒無響應、前臺廣播10秒、后臺廣播60秒、前臺Service 20秒、ContentProvider超時。但這些數值不是重點重點在于ANR是怎么判定的。面試官想聽的回答是系統通過消息機制檢測超時。比如輸入事件InputDispatcher會設置一個超時時間如果事件在隊列里長時間沒有被處理完就會觸發ANR。所以主線程阻塞才是ANR的真正原因。我當時為了準備ANR特意去看了自己項目里MainLooper現場的日志掌握了兩個關鍵信息一是日志會有main looper、input dispatching timed out這些關鍵詞二是要能判斷是死鎖、任務耗時還是Binder等待。有時候面試官會把ANR和Handler聯系起來為什么主線程必須有個Looper因為要不斷處理MessageQueue里的待辦事件比如輸入、布局、繪制三大塊。如果某個消息耗時太久后面的所有消息都會排隊輸入事件超時就被系統判定為ANR。4.2 內存泄漏常見場景和LeakCanary原理內存泄漏的八股大多數人都能說出幾個場景靜態變量持有Activity、Handler持有Activity、匿名內部類持有外部類、資源沒關閉、單例傳入Context。但面試官問為什么Handler持有Activity會造成泄漏很多人就開始含糊。正確答法是Handler在子線程發了一個延遲消息MessageQueue持有這個MessageMessage.target指向HandlerHandler又持有外部Activity的引用導致Activity無法被回收。回答LeakCanary怎么檢測泄漏時不要只說WeakReference要說出關鍵機制Activity.onDestroy之后LeakCanary會通過Application.ActivityLifecycleCallbacks拿到這個Activity把它放到一個WeakReference里然后過幾秒主動觸發一次GC如果WeakReference.get()還是不為null就說明發生了泄漏再通過ReferenceQueue做確認。這里還有一個加分點手動調用System.gc()并不一定立刻GCLeakCanary會等待IdleHandler空閑時再GC多次檢測后確認泄漏。這個細節體現你對GC和ART運行時有一定理解。4.3 卡頓監控從Choreographer到FrameCallback卡頓優化題基本會成為你的項目做過什么性能優化的引子。我準備的標準話術是卡頓的本質是掉幀也就是一幀的繪制超過了16.6ms。用Choreographer的FrameCallback可以拿到幀間隔如果兩幀之間的時間差大于16ms就說明有卡頓。但真正要定位是哪兒卡還需要用Systrace/Method Tracing抓主線程耗時。2022年有一些更細的考法比如為什么說渲染線程的耗時也算進掉幀 因為Android 5.0之后引入了RenderThreadChoreographer的FrameCallback只管App側實際發到GPU渲染由RenderThread負責如果GPU忙不過來即使主線程不卡也會丟幀。性能優化的八股里我還準備了一個非常實用的模板先用systrace看有沒有binder sync、layout、measure等明顯耗時。再看內存抖動頻繁創建對象導致GC頻繁用Memory Profiler抓Allocation。最后用BlockCanary或自研的Looper.getMainLooper().setMessageLogging哪個Message耗時超過閾值就記錄堆棧。這樣答出來會顯得你有完整的方法論而不只是背了一個掉幀概念。5. Jetpack與架構設計2022年面試的加分區5.1 MVVM 協程標配回答的完整版本2022年Android面試聊架構默認大家都會說MVVM。但要是只答數據驅動UIViewModel持有LiveDataView監聽LiveData那還是太單薄。一個七八分的回答應該是這樣UI層通過Activity/Fragment持有ViewModelViewModel暴露狀態UI使用觀察者模式監聽狀態變化數據的獲取放在Repository層遠程或本地數據源都通過Repository返回給ViewModelViewModel不持有View的引用所以屏幕旋轉時不會因為View重建而重建。再加一點協程可以替代部分LiveData的場景。LiveData是感知生命周期且自動管理但它在多線程和Flow復雜轉換上不如Kotlin Flow靈活。所以常見架構是UI層用LiveDataRepository以上用Flow這個表達在2022年大廠面試里非常常見。如果你再能說出ViewModel為什么能在Activity重建后保持存活就是加分完成了因為ViewModelStore在Activity里Activity被銷毀重建時非配置變更場景下ViewModelStore會保留只有finish時才會clear。5.2 生命周期組件與ViewModel原理被忽略的細節面試官有時會專門深挖Lifecycle原理問Lifecycle是怎么感知Activity生命周期的答案是在Activity的onCreate里通過ReportFragment.injectIfNeededIn(activity)注入一個無UI的Fragment利用Fragment的生命周期回調把Activity的生命周期事件分發出去。或者在新版本里Activity通過LifecycleRegistry調用handleLifecycleEventObserver就會被喚醒。另一個容易被問到的細節是onSaveInstanceState和ViewModel的區別。onSaveInstanceState適合保存臨時性的、可以被序列化的數據但如果是大對象或非序列化對象用ViewModel更合適。而且onSaveInstanceState在進程被系統殺死后還能恢復ViewModel在進程被殺死后不會存活所以兩者是互補的。準備這部分時我給自己出的一個驗證題是我實現一個自定義LiveData讓它在多個觀察者不同生命周期下正確分發事件怎么做 想通這個能應對大多數Lifecycle的追問。5.3 該不該提Compose新技術的面試尺度2022年7月問Compose大概率是一個印象題。面試官不指望你多精通但想知道你是否關注了新技術、有沒有實踐意識。我的建議是不要主動大篇幅說Compose除非你項目里真的用了。更安全的說法是我了解Compose的聲明式UI思想也看過它的重組機制但當前項目還是以View體系為主團隊還沒有引入Compose。然后可以聊Compose的核心優勢狀態驅動UI、重組只發生在State變化處、用Composable函數描述界面。如果你能補充一兩句副作用API的原理比如remember、LaunchedEffect、DisposableEffect的區分就更扎實了。但一定不要生拉硬扯聊到你不熟的地方非常容易露怯。6. 容易漏掉的邊角料考點類加載、混淆、adb與網絡6.1 Java/Kotlin細節泛型擦除與協程掛起在八股文篇里我把Java/Kotlin基礎單獨列了一類因為很多人在準備Android題時會忽略語言層的問題但2022年面試官喜歡混合考。Java層最容易考到的是泛型擦除編譯成字節碼時泛型類型會被擦除運行時拿不到真正的泛型類型。面試官會問我能不能通過反射拿到List 的類型參數答案是不能除非用TypeToken類庫來繞開。Kotlin協程這塊高頻考點是掛起函數的原理。掛起函數本質是狀態機編譯器會把一個掛起函數編譯成一個Continuation對象保存當前狀態和局部變量當掛起恢復時再繼續執行。我用一個答題金句掛起不是阻塞是把CPU讓出去等結果恢復后在原來的棧上繼續走而不是新開線程。6.2 R8與APK瘦身混淆規則的高級問法熱搜詞里出現了android r8和android studio混淆2022年面試也確實會問App優化的相關。先理解R8是干嘛的它是ProGuard的升級替代品負責代碼壓縮、資源壓縮、優化和混淆。通過obfuscate階段把類名、方法名改短減少包體積。常見的追問是R8和ProGuard有什么區別 答案R8把shrink裁剪、optimize優化、obfuscate混淆、desugar脫糖四步合并成一個統一的編譯期工具效率比ProGuardDX/D8高很多。APK瘦身的高頻問法包括為什么開啟android:extractNativeLibsfalse可以讓安裝包變小 因為壓縮andAlign庫可以減少占用空間。圖片資源為什么用WebP 同等質量下比PNG體積小。為什么可以配置shrinkResources 因為R8去掉無效代碼后關聯的未使用資源也可以被裁掉。6.3 adb與常用調試現場排錯的能力題不要小看adb命令面試官在問項目時經常順手考你怎么看一個App的當前Activity怎么查找ANR日志怎么判斷內存占用我整理我必背的一組命令adb shell dumpsys activity top查看當前界面Activity。adb shell dumpsys meminfo package查看進程內存占用。adb pull /data/anr/拉取ANR日志。adb shell kill -3 pid主動觸發一次ANR日志生成。adb shell am start -n package/activity拉起指定頁面。這些命令的回答要結合場景不要背菜單。比如你說自己排查過ANR就可以說先用dumpsys看主線程狀態和堆棧然后從/data/anr/traces里找到線程名和鎖等待關系。這樣面試官會覺得你確實干過而不是只會背命令。7. 八股文怎么答才有區分度從背題到聊體系7.1 面試官問八股的真實意圖面試官讓你介紹Handler機制他真實的目的是什么絕對不是想看你會不會背一遍源碼注釋而是想判斷你是否理解Android系統的消息循環模型能否應對系統為什么這么設計。遇到性能或異常問題時能否從機制層面推測根因。有沒有持續看源碼和深入思考的習慣。所以答題的時候不要一口氣把源碼全背出來要像講故事一樣先說模型再說為什么最后配合場景。要留給面試官追問的空間他說不定會接著你的回答問出更多細節。我在模擬面試時要求自己回答每個核心題都不超過80秒但在這80秒內必須包含一個結論、一個原理、一個例子。比如Handler結論是主線程靠LooperMessageQueue循環處理消息原理是nativePollOnce阻塞、epoll喚醒例子是postDelay不是定時器只是按時間排序插入到時間才從隊列取出。這樣的回答就比光背流程有區分度。7.2 被追問時的應對不要急著給出所有細節面試時最忌諱的是面試官一開口就把我所有知道的都倒出來結果他沒法再往下問。更自然的策略是先給到七分等追問再給到九分。舉例面試官問你了解AMS嗎你可以先答AMS是系統服務中管理Activity、Service、BroadcastReceiver生命周期和任務棧的核心類它在SystemServer進程里。如果面試官繼續問那它怎么和App通信你再展開Binder和ApplicationThread。他如果只問了第一層你就不要直接背到zygote避免顯得像在背課文。遇到不會的問題也要有一套話術這塊我平時沒有從源碼層面細看過但是根據我對xxx的理解我覺得大概和xxx有關。如果我有機會深入了解我會xxx。 這句話比硬編胡造強一百倍也比答不上來就沉默強很多。7.3 如果準備時間只剩兩周的個人建議最后分享一個適合沖刺的實操方案是我自己用著比較順的第1~3天把Handler、Binder、AMS這三個最硬核的機制徹底吃透每天拿一臺手機或者模擬器一邊看源碼一邊畫時序。第4~5天View事件分發和繪制流程用自己寫過的小Demo驗證。第6~7天性能優化三件套ANR、內存泄漏、卡頓和自己的項目結合。第8~9天Jetpack全家桶重點看ViewModel、LiveData、Lifecycle。第10~11天過一遍基礎語言題和網絡題刷一些面經。第12~13天模擬面試自己錄音回聽哪里有停頓、哪里表達不清。第14天查漏補缺把最不熟的三個點再背一遍。每天保證輸出別光看。我會把當天復習的題目用我自己講給自己聽的方式說一遍經常錄音之后發現真能順暢講三分鐘以上的知識點才算真的學會了。很多題目隔一天再講一次如果講不順就說明還需要回爐。八股文準備這件事說白了就是系統梳理 刻意輸出。你能把每個知識點用正常人聽得懂的話講清楚講到自己不覺得卡殼面試時大概率也不會出大問題。2022年7月這個時間點Android面試的要求是在變高但底層的那些機制沒變把基礎盤扎穩了后面聊項目、聊架構都會有底氣。