Daily Digest

每日新聞摘要

2026年05月20日

今日總結

內容會跟隨語言切換。

📝 今日焦點:測試應以狀態驗證為預設,並以真實假物件、合約測試取代過度 mock;AI 能加速實作,但 Clean Architecture 與基礎設計判斷仍是可維護系統的核心。 🏗 架構設計:Android 需依裝置形態重設 UI 與分層,TV、Wear OS、Auto 各有焦點、可視與安全限制;Compose 導航可用 NavKey 加 Hilt 做型別安全路由,狀態則應區分持久與短暫資訊。 🔧 效能最佳化:R8 可能刪除系統或反射間接使用的類別,release 必須實測;Room 檢索宜以 FTS 取代 LIKE,網路層則可藉 connection pool、HTTP/3、Protobuf 與 DoH 降低延遲。 ✅ 測試與品質:coroutine 測試應以 TestDispatcher 固定時序,Flow 可搭配 Turbine;另有多個品質警示,包括 release-only 失效、Google Play 權限審查,以及避免把實作細節寫進測試。

01

Advanced Mocking Strategies: Mastering Test Doubles & Behavior Verification

Dev.to Kotlin 作者:Patoliya Infotech 發布:05-20 12:14

進階模擬策略:掌握測試替身與行為驗證

Mocking 要解決的是軟體測試中的根本張力:在完全隔離下測試程式碼,同時它又不可避免地依賴外部世界。

重點摘要

區分 dummy、stub、fake、spy 與 mock 五種測試替身
預設採用狀態驗證,只有需要互動或副作用時才做行為驗證
提醒避免過度 mock、脆弱的互動斷言與深層 stubbing

本文從實務角度說明進階 mocking:先釐清 dummy、stub、fake、spy、mock 的差異,再比較狀態驗證與行為驗證,主張大多數情況以狀態驗證為預設,只有在協調流程、通知、事件發布或外部呼叫本身就是需求時,才檢查互動。文章也討論 partial mock、strict mock、deep stubbing、非同步流程,以及透過自有介面、合約測試與逼真的 fake 來測外部服務。最後整理常見反模式,如過度 mock、測試實作細節與不必要地 mock 第三方函式庫,強調可重構且能抓出真實問題的測試。

02

R8 Minification Silently Killed My Android App's Core Feature (And Tests Didn't Catch It)

Dev.to Kotlin 作者:Diven Rastdus 發布:05-20 12:31

R8 縮減靜默地毀掉了我的 Android App 核心功能

App 成功安裝、介面也正常顯示,但 AccessibilityService 從未向系統註冊。

重點摘要

R8 把看似未使用的系統註冊類別與 Hilt 入口點刪掉了。
CI 只測了 debug 版本,沒驗證啟用 minify 的 release 產物。
作者最後關閉 release 的 R8,並建議用 release 測試與 keep 規則防範。

作者分享一個令人錯愕的 Android 除錯經驗:CI 全綠、單元測試通過、release APK 也能成功安裝,但 App 的核心阻擋功能卻完全失效。問題出在 R8 縮減,它依照靜態呼叫圖刪除了由系統或反射間接啟用的類別,例如 AccessibilityService、覆蓋層 Activity 與 Hilt 入口點。由於測試只跑 debug 版本,release 專屬的錯誤沒被發現。作者雖然加上 keep 規則,最後仍選擇直接關閉 R8,認為這款開源 App 沒有足夠的隱私或逆向保護需求,卻承擔了額外風險。

03

Precise Android Camera Framing with CameraScaleType in ImagePickerKMP 1.0.41

Dev.to Kotlin 作者:Ismoy Belizaire 發布:05-20 14:12

在 ImagePickerKMP 1.0.41 中使用 CameraScaleType 精準控制 Android 相機取景

ImagePickerKMP 1.0.41 adds CameraScaleType, a small API with a practical impact: it lets Android developers control how the camera preview is scaled inside its viewport.

重點摘要

FILL_* 會裁切畫面以填滿視窗,FIT_* 會保留完整畫面並在需要時加上黑邊。
共提供六個列舉值:FILL_CENTER、FILL_START、FILL_END、FIT_CENTER、FIT_START、FIT_END。
透過 CameraCaptureConfig.cameraScaleType 設定,且屬於 Android 專屬功能。

ImagePickerKMP 1.0.41 新增 CameraScaleType,讓 Android 開發者能控制相機預覽在視窗中的縮放方式。文中說明 FILL_* 會裁切影像以填滿畫面,適合沉浸式相機或社群拍攝;FIT_* 則會保留完整畫面並在必要時顯示黑邊,較適合收據、證件、標籤等需要精準取景的流程。作者也指出 FIT_CENTER 是重視預覽可信度時的穩健預設,而 FILL_CENTER 則保留原本行為。此設定可透過 CameraCaptureConfig.cameraScaleType 使用,並能與壓縮、EXIF、UI 與權限設定一起配置。

04

Durable State vs Ephemeral UI State in Android

Medium Kotlin 作者:Rituraj Sambherao 發布:05-20 07:11

Android 中的持久狀態與短暫 UI 狀態

如何判斷應用程式需要記住什麼,以及哪些資訊可以安全地忘記。

重點摘要

說明持久狀態與短暫 UI 狀態的差異。
協助判斷哪些內容應保留、哪些可以丟棄。
聚焦於 Android 狀態管理的實務決策。

本文探討 Android 應用程式中的持久狀態與短暫 UI 狀態之間的差異,並回答一個常見問題:哪些資訊應在程序死亡或設定變更後仍被保留,哪些只屬於當下畫面互動、可以在結束後遺忘。文章重點在於協助開發者判斷應用程式需要記住什麼、哪些內容可以安全地忘記,讓 Android 的狀態管理更穩定且易於維護。

05

How to Handle Disabled State for Multicolour Icons in Android (Jetpack Compose Guide)

Medium Kotlin 作者:inDrive.Tech 發布:05-20 08:41

在 Android 中處理多色圖示的停用狀態(Jetpack Compose 指南)

UI 的停用狀態原本很單純——直到你遇到多色圖示為止。

重點摘要

停用狀態在概念上簡單,但多色圖示會增加處理難度。
文章聚焦於 Android Jetpack Compose 的實作情境。
主題在於圖示呈現與停用狀態之間的設計與實作問題。

本文指出,Android 的 UI 停用狀態通常不難處理,但當圖示是多色時,就會變得更複雜。文章以 Jetpack Compose 為脈絡,強調需要一種實用做法,讓圖示在維持原本外觀的同時,也能清楚傳達已停用狀態。內容主要是在提出問題並引出對多色圖示處理方式的指南。

06

How to Fix Google Play READ_MEDIA_IMAGES Rejection After Removing the Permission

Medium Kotlin 作者:Kevin Malik Fajar 發布:05-20 09:36

移除 READ_MEDIA_IMAGES 權限後,如何修正 Google Play 拒絕問題

最近,我遇到了一個與相片和影片權限政策相關的 Google Play 政策拒絕。

重點摘要

拒絕原因與 Google Play 的相片和影片權限政策有關。
問題發生在移除 READ_MEDIA_IMAGES 權限之後。
文章主旨是說明如何解決這項政策拒絕。

作者說明自己在移除應用程式的 READ_MEDIA_IMAGES 權限後,遇到了 Google Play 的政策拒絕。這項拒絕與 Google Play 的相片和影片權限政策有關,顯示即使權限已移除,仍可能觸發合規檢查。文章被定位為一篇供開發者參考的修正指南,但目前提供的摘要片段未包含實際解法細節。

07

Data Structure : Graph

Medium Kotlin 作者:Awadhesh Singh 發布:05-20 09:56

資料結構:圖

學習路徑.第 1 部分

重點摘要

介紹圖這個主題
屬於學習路徑系列文章
更多內容請繼續閱讀 Medium 原文

這篇文章看起來是資料結構學習路徑的第一部分,主題聚焦於圖(Graph)。由於目前提供的內文非常簡短,只能確認它屬於系列文章的開端,並引導讀者前往 Medium 繼續閱讀。從標題與片段判斷,內容主要是為後續圖的基礎概念建立導讀。

08

Buffer Reading and Writing in Kotlin

Medium Kotlin 作者:Kabi 發布:05-20 10:01

Kotlin 中的緩衝區讀寫

在數位世界裡,速度就是一切。

重點摘要

文章介紹 Kotlin 的緩衝區式 I/O。
內容承接先前的基本 I/O 串流指南。
開頭強調數位資料處理中速度的重要性。

本文〈Kotlin 中的緩衝區讀寫〉介紹如何在 Kotlin 中運用緩衝區來提升輸入輸出效率,並承接先前關於基本 I/O Streams 的內容,將緩衝處理定位為更有效率處理資料的下一步。摘錄開頭指出數位世界中速度至關重要,暗示透過緩衝讀寫,可在面對較大或更複雜的資料流時,改善效能與處理效率。

09

Day 8: Null Safety — The Feature That Made Kotlin Famous

Medium Kotlin 作者:Kirubakaran 發布:05-20 10:54

第 8 天:Null 安全性——讓 Kotlin 聞名的功能

Null 安全性是幫助 Kotlin 廣為人知的核心特色。

重點摘要

屬於 Android with Kotlin for Absolute Beginners 系列
主題聚焦 Kotlin 的 Null 安全性
為系列第 8 天內容

本文為「Android with Kotlin for Absolute Beginners」系列的第 8 篇,主題聚焦於 Kotlin 的 Null 安全性,也是常被視為讓 Kotlin 廣為人知的關鍵功能。由於目前提供的內文只有標題與「Continue reading on Medium」提示,沒有更多技術細節、範例或論述,因此可確定的內容僅限於這是一篇介紹或延續討論 Kotlin Null 安全性的系列文章。

10

AI Can Write Code, So Why Should Developers Still Learn Structured Programming, OOP, and Functional…

Medium Kotlin 作者:Ashish Singh 發布:05-20 11:57

AI 能寫程式,但開發者仍需學習核心程式設計基礎

《Clean Architecture》讓我明白,到了 AI agents 的時代,軟體基本功或許反而更重要。

重點摘要

AI 可以產生程式碼,但無法取代工程判斷。
結構化程式設計、OOP 與函數式思維仍有助於清晰思考。
Clean Architecture 提醒我們:當 AI 融入流程後,基本功更顯重要。

這篇文章主張,即使 AI 已能撰寫程式,開發者仍必須理解核心程式設計範式與軟體基本功。作者以 Clean Architecture 的體會為例,指出 AI 或許能加快實作,但不能取代清楚思考、可維護的設計,以及對取捨的判斷能力。結構化程式設計、物件導向與函數式觀念,能幫助開發者組織複雜度,打造更容易理解、測試與演進的系統。在 AI agents 時代,這些基礎可能不是變得不重要,而是更加重要。

11

Explain recomposition — what triggers it and how to minimize it?

Medium Kotlin 作者:Kamaldeep Kakkar 發布:05-20 13:30

解釋 Recomposition:是什麼觸發它,以及如何將其降到最低

這是在真正理解 Compose 時最重要的事情之一。

重點摘要

說明 Jetpack Compose 中 recomposition 的基本概念
整理常見的 recomposition 觸發因素
探討減少不必要 recomposition 的方法

這篇文章介紹 Jetpack Compose 中的 recomposition,並強調理解它對於寫好 Compose 應用非常重要。內容聚焦於 recomposition 的定義、會觸發它的常見情況,以及開發者如何減少不必要的重新組合,以提升程式可讀性與效能。文章將其視為深入理解 Compose 的關鍵主題之一。

12

Testing Coroutines Without the Pain: TestDispatcher, Turbine, and Deterministic Flow Tests

Medium Kotlin 作者:Dev 175 發布:05-20 13:48

告別痛苦的 Coroutine 測試:TestDispatcher、Turbine 與可決定性的 Flow 測試

你的 coroutine 測試之所以不穩定,是因為它們在和真實時間競賽。

重點摘要

Coroutine 測試不穩定,常見原因是真實時間介入。
TestDispatcher 可讓 coroutine 執行更可控、更具決定性。
Turbine 有助於穩定驗證 Flow 的發射結果。

本文指出,coroutine 測試之所以容易出現不穩定結果,主要是因為它們依賴真實時間與無法掌控的排程。作者建議透過 TestDispatcher 來控制 coroutine 的執行,使測試具有決定性,而不是與時鐘競賽。同時也介紹 Turbine 可用來穩定驗證 Flow 的發射內容。整體重點是停止猜測時間行為,改以可重複、可預期的方式撰寫 coroutine 與 Flow 測試。

13

New big challenger in UI development

KT Academy 作者: 發布:05-11 00:00

UI 開發的新大型挑戰者

Compose 正在改變 UI 開發的遊戲規則。

重點摘要

Compose 被描述為 UI 開發中的新重要力量。
文章聚焦於 Compose 如何改變開發格局。
原文內容簡短,重點在於提出這個主題。

本文以簡短文字介紹 Compose 在 UI 開發中的新角色,將其定位為一個重要的挑戰者。原文沒有展開技術細節,而是強調 Compose 正在改變使用者介面的開發方式與整體格局。整體來看,文章重點在於點出 Compose 對 UI 開發領域的影響與潛力。

14

What are cohort courses?

KT Academy 作者: 發布:05-18 00:00

什麼是 cohort 課程?

學習形式的演進,從書籍、工作坊到 cohort 課程。

重點摘要

學習形式隨時間持續演進。
書籍與工作坊屬於較早期形式。
Cohort 課程是文中提到的新階段。

本文以學習形式的演進為主軸,將 cohort 課程放在更大的教育發展脈絡中來看。內容指出,學習方式從書籍、工作坊一路演變到 cohort 課程,暗示以 cohort 為基礎的學習是教育型態持續更新的一環。由於原文相當簡短,並未進一步說明 cohort 課程的運作方式,但已清楚表達其在學習方法轉變中的位置。

15

Effective Search in RoomDB: FTS vs LIKE

ProAndroidDev 作者:ValentineRutto 發布:05-19 23:20

RoomDB 的有效搜尋:FTS 與 LIKE

對於像聖經經文這類大型資料集,LIKE 會因為反覆掃描資料列而變得低效。

重點摘要

FTS 採用索引式全文搜尋,處理大量文字資料時比 LIKE 更快。
可用 contentEntity 將一般資料表與 FTS 索引表連結,分工明確。
即時搜尋建議搭配 debounce,避免使用者每輸入一個字就查詢資料庫。

本文以聖經 App 為例,比較 RoomDB 中的 LIKE 與 SQLite Full-Text Search(FTS)。作者指出,LIKE 對小型資料表尚可,但在大量經文這類文字資料上會因反覆掃描而效能下降;FTS 則透過索引進行搜尋,速度更快,也支援排序與片語、前綴查詢。文章示範如何建立儲存真實資料的 verses 表,以及透過 contentEntity 連結的 verses_fts 搜尋索引表,再以 MATCH 完成高效率查詢。同時也提到 Flow 可讓 UI 自動更新,而 live search 應加入 debounce,以減少不必要的資料庫負擔。

16

Android Beyond the Phone: Lessons from Building for TV, Auto, and Wear

ProAndroidDev 作者:Siarhei Krupenich 發布:05-19 23:23

超越手機的 Android:從 TV、車載與 Wear 開發學到的事

如何透過 Jetpack Compose、Wear OS 與 Car App Library,在不同裝置間共享商業邏輯並打造專屬 UI 體驗。

重點摘要

不要把手機 UI 直接拉伸到 TV、手錶或車載環境。
將共用商業邏輯放進純 Kotlin 的 domain 層,平台模組保持精簡。
分別因應 TV 的焦點、Wear 的一瞥式互動,以及 Auto 的安全限制。

這篇文章指出,Android 開發不能再預設只有手機、觸控與充足注意力。作者以 TV、Wear OS 與 Android Auto 為例,說明不同形態的裝置需要不同的 UI 思維:TV 重視 10 呎距離的瀏覽與 D-pad 焦點管理;Wear OS 強調可快速理解、低耗電的一瞥式體驗,如 Tiles 與圓形版面;車載則必須使用模板化介面,並嚴格控制分心風險。文章主張把共用業務邏輯抽到純 Kotlin 的 domain 層,讓各平台 app 保持薄而清楚,再依裝置特性實作對應 UI。核心觀念是:不要複製手機介面,而要針對硬體、輸入方式與生命週期限制做設計。

17

What Really Happens When Your Android App Makes an API Call

ProAndroidDev 作者:MD Ibrahim Khalil Shakir 發布:05-19 23:24

當 Android App 發出 API 呼叫時,究竟發生了什麼事

從 socket、TLS 到 HTTP/3、DNS-over-HTTPS 與憑證釘選,完整拆解 API 請求在 OS 層級的旅程。

重點摘要

完整說明請求與回應如何穿越應用層、核心、網路與硬體。
比較連線池、HTTP/3、Protobuf、DoH 等效能優化手段。
涵蓋 Doze 模式、省電、回壓,以及安全的憑證釘選做法。

本文拆解 Android 網路通訊的底層流程,說明當 Retrofit 或 OkHttp 送出請求後,資料如何經歷 DNS 解析、TCP 與 TLS 握手、封包切分與傳輸,再在回應抵達時透過中斷、核心緩衝區、執行緒切換與主執行緒派發回到 UI。接著作者整理大規模應用常見的優化策略,包括調整 ConnectionPool、避免 Nagle 延遲、以 Cronet 導入 HTTP/3、以 Protobuf 或 FlatBuffers 取代 JSON、使用 DNS-over-HTTPS,以及透過 DNS pinning 與憑證釘選提升安全性。文章也提醒行動裝置上的 Doze、省電、回壓與重試策略等限制。

18

The Type-Safe Pattern Without SavedStateHandle : Hilt Assisted Injection with Jetpack Navigation 3

Medium Kotlin 作者:chanzmao 發布:05-19 23:21

不使用 SavedStateHandle 的型別安全模式:Jetpack Navigation 3 的 Hilt Assisted Injection

透過 NavKey 與 AssistedInject 建立 route-scoped ViewModel,讓 Compose 導航更乾淨、也更具編譯期安全性。

重點摘要

使用 NavKey 將 ViewModel 綁定到特定路由
結合 Hilt AssistedInject 與 Jetpack Navigation 3
提升 Compose 導航的可讀性與編譯期安全性

本文介紹一種在 Compose 導航中避免使用 SavedStateHandle 的型別安全做法,核心是結合 NavKey 與 Hilt AssistedInject。作者說明如何建立與路由綁定的 ViewModel,讓導覽流程更清楚、狀態處理更簡潔,並在編譯期就提供更好的安全性。這提供了 Jetpack Compose 導航的一種實用替代方案。

19

The Turning Point: Why Google Just Placed the Legacy Android View System on Life Support

Medium Kotlin 作者:Mohilvadia 發布:05-20 06:20

轉折點:為什麼 Google 將舊版 Android View 系統置於維生狀態

如果你最近有在 Android Studio 內工作,應該已經注意到建立新專案的流程看起來有些不同。

重點摘要

Android Studio 的新專案流程已出現變化。
文章指出,Google 正在淡化舊版 Android View 系統的重要性。
原文摘要僅提供導讀,完整內容需前往 Medium 閱讀。

文章指出,最近在 Android Studio 中建立新專案的介面與流程已有所不同,暗示 Google 對 Android 開發方向正在進行調整。雖然目前可見的內文很短,但標題與導語都指向一個明確訊號:傳統的 Android View 系統正被逐步降為次要地位。作者邀請讀者前往 Medium 繼續閱讀完整分析。