
2023年春招季我完整走了一遍小滿科技Android研發崗的筆試流程。這家公司在外貿CRM領域做了很多年移動端業務復雜度不算低所以筆試題目也比較貼近真實業務場景。整場筆試線上進行90分鐘包含了客觀題、編程題、簡答題和一道開放設計題。考完復盤下來我的感受是題型不偏但每類題都在考察你是否真的做過項目而不是單純背過面試題。這篇東西就把我記錄的題目方向、答題思路和一些踩坑經驗整理出來給后面準備Android春招的朋友做個參考。1. 筆試整體情況與題型結構分析1.1 考試形式、環境與客觀題分布小滿這場筆試用的在線考試系統瀏覽器里直接寫代碼不能本地切IDE所以平時習慣依賴Android Studio自動補全的人會稍微難受一點。我進場前特意把常用API的拼寫和關鍵方法名在腦子里過了一遍避免寫代碼時卡在記憶細節上。建議后面參加筆試的同學也提前看下考試平臺支不支持本地編輯器如果不支持提前適應純手寫代碼的節奏。客觀題部分是整套卷子的基礎盤我當時數了一下大概25題左右覆蓋了Java基礎、Android基礎、網絡協議和數據結構四大塊。Java部分考了集合源碼、線程安全、JVM內存分區、類加載流程Android部分集中在Activity生命周期、啟動模式、Handler、Binder、View繪制流程這些經典考點。網絡層問到了TCP三次握手、HTTP緩存機制、HTTPS證書校驗流程都是老熟人。整體難度不算高但多選題有個比較坑的規則少選得分、錯選不得分所以拿不準的選項我寧可空著也不亂選。題型分布我整理成了下面這張表可以直接對照著查漏補缺題型題量考察范圍難度感受單選/多選約25題Java、Android、網絡、數據結構中等偏易編程題11題貪心/動態規劃、邊界處理中等LeetCode中等偏下編程題21題并發任務調度、線程池、回調中等偏上區分度高簡答題約2題Handler線程模型、組件通信偏原理靠理解開放設計題1題模塊化架構、Jetpack選型靠項目經驗1.2 編程題與簡答題的難度分級兩道編程題第一道是區間調度問題給定一組商品上架的時間區間求最多能安排多少個不重疊的區間本質是經典貪心按結束時間排序后逐個取。這題LeetCode上類似題很多平時刷過基本沒問題。第二道題就很有Android特色了——讓實現一個支持并發數限制和結果回調的任務執行器。這道題沒有標準答案考察的是線程池參數、任務隊列、FutureTask、回調線程切換這些實戰能力我在第3章會專門展開講。簡答題有一道是“如何設計一個支持多模塊的App”不要求寫代碼但要有清晰的方案。這類題的核心是架構分層和模塊邊界劃分能看出來面試官在乎的是候選人有沒有系統設計意識。另一道是Handler相關要求描述從子線程發送消息到主線程處理消息的完整鏈路并說明哪些環節容易出現內存泄漏。1.3 這場筆試想篩選什么人從整套題目的結構反推小滿的用人畫像比較清晰第一基礎要扎實Java和Android底層機制不能停留在“會用”層面得能說出原理第二要有真實項目經驗內存泄漏排查、列表卡頓優化、組件化改造這些經歷過的最加分第三要有設計意識哪怕沒做過大型項目也要能對著業務場景畫出清晰的模塊邊界和數據流。這三個點后面我會逐個展開怎么準備。2. 核心考點拆解從四大組件到Handler機制2.1 Activity啟動模式不要只背四種模式Activity的四種啟動模式——standard、singleTop、singleTask、singleInstance是Android筆試的固定嘉賓。但小滿這批題問得更細直接把我問懵了一下singleTask配合taskAffinity使用時Activity會被轉移到哪個任務棧launchMode在Intent中設置flag之后誰優先生效onNewIntent的回調時機和觸發條件是什么我建議后來備考的朋友不要死記定義而是從任務棧操作的角度去理解。standard模式就是每次startActivity都new一個實例壓入當前任務棧singleTop是“如果要啟動的Activity已經在棧頂直接復用”singleTask是“目標Activity所在任務棧里如果已存在該實例就把它上面的Activity全部出棧”singleInstance是整個系統只有一個實例并且這個Activity獨占一個任務棧。理解了這四個場景再結合taskAffinity、FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_CLEAR_TOP去記憶搭配效果會順手很多。具體來說taskAffinity默認跟application一致singleTask模式下如果指定了不同的taskAffinityActivity會嘗試去那個任務棧找實例找不到就在那個棧創建。Intent里設置的FLAG_ACTIVITY_NEW_TASK優先級要高于Manifest里的launchMode這個細節是單選題的常客我當時看到題目第一反應就是“好在專門記過這一條”。2.2 Handler、Binder與線程模型把消息機制講成一條鏈路Handler機制幾乎是所有Android筆試必考小滿也不例外。我備考時習慣把這一塊講成一條完整鏈路應用啟動時ActivityThread會創建主線程的LooperLooper內部維護一個MessageQueueHandler通過sendMessage將Message入隊Looper.loop()循環取出消息回調Handler的handleMessage。整個過程用一句話概括就是用MessageQueue連接了生產者和消費者用ThreadLocal保證了每個線程只有一個Looper。筆試里關于Handler的高頻坑有兩個。第一個主線程能不能在子線程創建Handler答案是不能直接創建除非在該子線程中先調用Looper.prepare()再調用Looper.loop()這樣這個子線程才有了自己的Looper和消息隊列。第二個內存泄漏怎么產生的內部類Handler默認持有外部Activity引用如果MessageQueue里有延遲消息就會阻止Activity回收。標準答法是“使用靜態內部類加WeakReference并在onDestroy中移除回調”但如果你能補充一句“還可以用Lifecycle把任務綁定到生命周期或者用協程的MainScope來代替Handler”那就能讓面試官看到你對現代寫法的關注。Binder部分考了一道關于進程間通信的選擇題。我的理解是Binder基于mmap機制做了一次數據拷貝相比傳統的管道和共享內存它在安全性和性能之間做了很好的平衡。SystemServer進程作為核心服務管家AMS、WMS、PackageManager都跑在里面App進程通過Binder代理調用這些服務。這一套如果能在簡答題里畫出來從App調用到AMS仲裁再到應用啟動的鏈路基本就把面試官的胃口吊起來了。2.3 JVM、并發與引用類型Java基礎題的深層邏輯客觀題里Java并發相關的比例不低。synchronized和Lock的區別、volatile的可見性、ThreadLocal的實現原理、線程池的參數含義這些幾乎年年都考。準備這一塊時別只背結論要去想“為什么”。比如volatile它有三個語義保證可見性、禁止指令重排、但不保證原子性。筆試里如果考volatile和synchronized的區別別只答“volatile不能保證原子性”最好能舉出一個具體場景——兩個線程對一個long類型變量做自增用volatile修飾后仍然可能丟值因為自增操作本身不是原子操作。這就是“會說”和“會答”的區別。JVM部分小滿的題集中問了內存分區堆、棧、方法區/元空間、程序計數器、本地方法棧、對象創建過程、GC Roots、四種引用類型的區別。關于引用類型Android開發中更常接觸到的是內存緩存和圖片庫我建議結合LruCache和Bitmap的例子去理解軟引用與弱引用的適用場景。比如Bitmap在Android 2.3時代經常用SoftReference做內存緩存后來因為軟引用對象被GC回收得過于積極才換成了LruCache這種基于LRU算法的強引用緩存方案。這樣答出來會比干巴巴背定義豐富得多。3. 代碼題、架構題與Android Studio工具鏈考察3.1 手寫代碼題從算法到異步任務調度筆試環境里寫代碼最重要的不是你寫得多花哨而是邏輯清晰、邊界完整。第一道區間調度題我的思路是貪心把所有區間按結束時間升序排序然后遍歷如果當前區間的開始時間大于等于上一個已選區間的結束時間就選取它。我在提交前還特意補了兩個邊界用例——空數組和只有一個區間的情況并且把時間復雜度和空間復雜度寫在注釋里。這些細節在線上筆試的判分里未必直接加分但面試官看回放時會注意到。第二道題“實現一個支持并發數限制和結果回調的任務執行器”是整套卷子真正拉開差距的地方。我的實現方案是public class LimitedTaskExecutor { private final ExecutorService executor; private final Handler mainHandler; public LimitedTaskExecutor(int maxConcurrent) { this.executor new ThreadPoolExecutor( maxConcurrent, maxConcurrent, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue(100), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); this.mainHandler new Handler(Looper.getMainLooper()); } public T void submit(CallableT task, CallbackT callback) { FutureTaskT futureTask new FutureTask(() - { T result task.call(); mainHandler.post(() - callback.onSuccess(result)); return result; }); executor.execute(futureTask); } public interface CallbackT { void onSuccess(T result); } }這套方案用有界隊列加CallerRunsPolicy既能限制并發數又不會因為任務堆積導致OOM回調切回主線程也符合Android UI更新的要求。能想到這層的候選人不多我當時注意到這場筆試里很多人第二題都是空著的所以把這題寫完整非常值。3.2 架構設計題Jetpack MVVM與模塊化思路“如何設計一個支持多模塊的App”這道簡答題我把它當成了一場小型系統設計的口頭表達。我的答題框架是從分層架構開始——數據層用Repository封裝Room、Retrofit的數據來源領域層放UseCase展示層用ViewModel加Compose或者XML加DataBinding再做模塊化拆分——按業務拆成訂單、客戶、報表等獨立模塊模塊間通過路由框架解耦跳轉最后補充組件化編譯優化思路。這里有個容易被忽略的點Jetpack 組件之間的生命周期綁定原理。LiveData和ViewModel為什么能自動感知生命周期ViewModelStore里存有ViewModel實例配置變更時Activity被重建但ViewModelStore會在舊Activity銷毀之前傳遞給新的ActivityLiveData的observe是在主線程回調數據變化時通過LifecycleOwner判斷當前是否活躍不活躍時不會回調。這兩個細節我在筆試里都寫了出來這種“知道但說不清”的點恰恰是區分簡歷水分的關鍵。模塊化問題如果只答到“分成多個module、用ARouter跳轉”就太淺了。我當時補充了資源前綴管理、依賴版本統一、模塊間通信使用接口而不是直接依賴實現類以及基礎庫和業務庫的分層關系。這些具體方案比空談原則更能打動面試官。3.3 工具鏈與測試AGP、R8、單元測試這些容易被忽略的點熱搜詞里出現了很多Android Studio相關的詞比如AGP版本、Android Studio Hedgehog等。筆試雖然不會直接問“AGP 8和7有什么區別”但在代碼壓縮、構建配置相關的題目里會隱晦地涉及。我的經驗是至少要熟悉AGP從3.4之后默認用R8作為壓縮器minifyEnabled控制是否開啟代碼壓縮shrinkResources可以配合R8移除無用資源。如果簡歷寫了“精通構建優化”這幾點就是必答項。R8的keep規則也是熱門考點我在備考時整理了項目里常用的一份筆試里用上了-keep class com.example.api.** { *; } -keepclassmembers class * { android.webkit.JavascriptInterface methods; } -keepattributes Signature, InnerClasses, EnclosingMethod這句話的意思是被接口定義或反射調用的類不能被混淆帶注解的方法要保留原名。能主動寫出具體規則比只會說“加keep”要扎實得多。測試相關的小滿分也考了問的是如何保證核心業務代碼質量。我答了單元測試用JUnit加MockitoUI測試用Espresso關鍵路徑用Robolectric在本地跑數據層網絡請求用MockWebServer模擬。筆試后面試官還追問了一句ViewModel要測什么答案是測狀態變化和生命周期行為不涉及Android Framework依賴所以JUnit環境下可以直接跑。這個補充點一下就接上了話題。4. 進階與冷門考點性能優化、系統服務、硬件交互4.1 性能優化內存泄漏、ANR、卡頓排查怎么答性能優化幾乎是所有大廠筆試題的常駐嘉賓小滿這場也不例外。客觀題里有一道問“ListView和RecyclerView的緩存機制差異”簡答題則讓描述一次線上OOM的排查過程。我當時的答題思路是先通過logcat確認異常線程和堆棧再用Android Studio的Profiler抓內存快照用LeakCanary輔助定位泄漏對象最后結合MAT分析引用鏈。這個流程是最常規、最穩妥的答法。ANR的排查也要會。筆試問的是“App主線程卡頓太久會觸發什么為什么”答案是Activity超過5秒未處理完輸入事件、BroadcastReceiver超時10秒、Service超時20秒都會觸發ANR。排查時先用adb shell dumpsys activity processes查看ANR日志位置再通過trace文件定位主線程阻塞點。如果能在答案里點名“主線程不能做IO、不能做復雜計算、不能用同步鎖等待子線程”就已經及格了。關于卡頓優化RecyclerView是繞不開的話題。我補充了三種優化手段用DiffUtil減少無謂的notify用ConstraintLayout減少嵌套層級用setHasFixedSize避免重新測量布局。這些點不一定全考但答出來能讓面試官覺得你不是只背了面試題而是真的在項目里處理過卡頓問題。4.2 AMS與系統服務多進程與Binder的隱性考點熱搜詞里出現了android ams這批筆試雖然沒有直接考AMS的單獨題目但在開放設計題“如何設計一個多進程App”里會隱性地用到。多進程場景下AMS是進程間通信的中樞。Activity的啟動、任務棧管理、進程調度、ContentProvider的發布都要經過AMS統一仲裁。如果你能提到AMS通過Binder和App進程通信system_server進程持有AMS實例Binder線程池的競爭會影響啟動速度那這題基本就穩了。ContentProvider作為進程間數據共享的組件也被問到了。關鍵在于ContentProvider的onCreate時機是App冷啟動時比Application.onCreate更早所以MultiDex和初始化的任務經常放在ContentProvider里做。這種藏著坑的題沒有真正經歷過組件初始化順序問題的人很難答對。4.3 藍牙、IoT與系統更新硬件與系統機制的延伸問題現代Android開發離不開硬件交互筆試里也出現了關于藍牙的低頻考點問的是經典藍牙和低功耗藍牙的核心差異。我答的方向是經典藍牙RFCOMM通道適合持續傳輸大數據BLE基于GATT協議主打低功耗和短連接連接間隔可配置適合物聯網傳感器場景。藍牙權限從Android 12開始做了細化ACCESS_FINE_LOCATION在部分版本上仍然是掃描藍牙必須的權限這個點我在實際項目里踩過坑寫出來明顯比其他候選人更有說服力。OTA和APEX這類系統級更新話題更多出現在Framework開發和系統應用崗位。作為應用崗筆試不一定會出題但如果簡歷里寫了了解系統機制就可能被追問。我對APEX的理解是Android 10引入的一種系統組件封裝格式相當于把系統服務從系統分區里獨立出來允許以類似App更新的方式去升級不需要完整OTA。這個知識點可以當業余加分項準備不建議占用太多時間。5. 時間分配、答題策略與踩坑實錄5.1 90分鐘怎么分配這場筆試我最想強調的就是時間分配。我給自己定的預算是客觀題35分鐘、編程題30分鐘、簡答題和開放題25分鐘最后留5分鐘檢查。客觀題里多選題如果是少選得分、錯選不得分遇到不確定的選項寧可少選。編程題哪怕沒法完全AC也一定要把思路寫進注釋里框架代碼先搭好再逐步細化這樣至少能拿到大部分過程分。時間分配表如下模塊建議時間操作要點單選/多選35分鐘不確定的選項不選快速推進編程題110分鐘貪心/DP題先寫邊界再寫主邏輯編程題220分鐘并發調度題把類結構和回調先搭好簡答題10分鐘用流程圖或分段回答別長編大論開放設計題10分鐘畫架構圖寫模塊邊界和數據流最后檢查5分鐘確認沒有空題檢查編譯錯誤這套時間分配的關鍵是不要把時間卡在選擇題上選擇題做得再漂亮也就單選兩分編程題的一步思路可能就抵得上好幾道選擇。5.2 遇到不會的題怎么處理有些題真的不會怎么辦我的做法是“分步拆解給出可推理的部分”。比如有一道關于RecyclerView預取機制的問題我記得原理是Prefetch在空閑幀預創建和綁定下一幀要顯示的ViewHolders但細節記不清了。我就先把“預取發生在空閑期”“減少了首幀的創建耗時”寫上去再結合LinearLayoutManager的布局時機補充了兩句。基于已知推理未知比空著不答強得多。另一道關于LiveData粘性事件的題一開始也把我卡住了。粘性事件的意思是先設置數據、后注冊觀察者觀察者也能立刻收到最后一次數據。如果不想讓新注冊的觀察者收到歷史數據可以引入SingleLiveEvent或者用Flow的SharedFlow配合replay0處理。這類題要是平時沒接觸過現場很難推出來但至少能先承認見過類似方案再往“生命周期分發時機”的方向上靠。5.3 筆試后的復盤與面試銜接筆試結束不等于萬事大吉。我在交卷后馬上把還記得的題目記錄了一遍挨個對照官方文檔和源碼確認答案。這里特別推薦重新看一遍Handler和ActivityThread的源碼因為簡答題里寫到的Looper.loop()和handleMessage的回調時機源碼里就是最準確的答案。這個復盤過程同時是為后面的面試做準備——筆試中考過的點面試官很喜歡接著追問。我個人的體會是整套小滿試卷的傾向其實和很多中大廠一致基礎理論要扎實、項目經驗要真實、設計思路要清晰。如果你正在準備Android春招不妨按這個方向把知識體系過一遍尤其是把每個知識點都能講出一個具體的業務場景。能講出場景才說明你真的用過能用原理解釋場景才說明你真的理解。這兩步都做到了不管是小滿的筆試還是其他公司的面試都會輕松很多。