Daily Digest

每日新聞摘要

2026年03月22日

今日總結

內容會跟隨語言切換。

📝 今日焦點:以 MVVM 將 UI 與邏輯分離以降低旋轉導致的資料遺失,並修正 Compose 重組相關的陳舊 lambda 與 Firestore 背後監聽洩漏。 🔧 效能最佳化:Shredzilla v1.1 重構移除長存監聽與改用 rememberSaveable,v1.2 專注離線同步、零延遲計時、搜尋去抖與列表優化並移出分析運算至非主線程。 🏗 架構設計:說明 val 為不可重新賦值的參考但非深層不可變、示範改進的 Result 類型實作、SharedPreferences 的簡易會話管理與跨平台 DI(Swinject/Hilt)比較。 🚀 語言演進:比較 Java、Kotlin 與 Scala 在語法簡潔性、函式式特性、生態工具與 JVM 互操作性的取捨,建議依專案需求選擇語言。

01

Understanding App Architecture - Why It Matters

Dev.to Kotlin 作者:Babiyashini Varadaraj 發布:03-20 05:11

理解應用程式架構:為何重要

能執行的程式碼與結構良好的程式碼之間存在差異。

重點摘要

良好架構能分離責任,提升可維護性。
MVVM 將 View、ViewModel、Model 各司其職,避免把所有邏輯塞進 Activity。
缺乏架構會使測試、擴充與團隊協作變得困難。

作者以課堂上的 BMI 計算器為例,說明從「能跑就好」到重視架構的心路歷程。原始範例把輸入取得、驗證、BMI 與體脂計算、分類、顏色與圖片決定、畫面更新等十多項工作塞在一個 Activity 的函式中,導致除錯與擴充很吃力。文章介紹 MVVM(View 顯示、ViewModel 管理畫面資料、Model 提供資料來源)如何解決旋轉導致資料遺失、程式碼重複與測試困難等問題。作者也列出在無架構的大型專案中常見的問題:程式碼混亂、團隊協作衝突、功能新增風險高、測試難以進行與除錯成本上升。個人經驗(儲存/還原鍵名錯誤)進一步強調從一開始就考慮架構的重要性。

02

Scaling Shredzilla: Slaying Memory Leaks & Mastering State in Jetpack Compose

Dev.to Kotlin 作者:freerave 發布:03-22 09:14

擴展 Shredzilla:剿滅記憶體泄漏並精通 Jetpack Compose 的 State 管理

v1.1.0 重構修復了 Firestore 監聽器洩漏,將長跑作業移入 ViewModel 並強化導覽與設定更新流程。

重點摘要

緩存並在登出時移除 Firestore ListenerRegistration 以修復記憶體洩漏
將非冪等作業放入 viewModelScope,並於 UI 使用 rememberSaveable 保存輸入
使用 popUpTo 清除認證回溯堆疊,並以單一 helper 抽象設定更新

Shredzilla 在 v1.1.0 以穩定性與可維護性為核心進行重構:發現並修正 Firebase Firestore 的 addSnapshotListener 造成的背景監聽器洩漏,透過在 UserDataManager 中緩存 ListenerRegistration 並在登出或刪除帳號時逐一移除來釋放資源;將帳號刪除與檔案清理等非冪等操作移至 MainViewModel 的 viewModelScope,避免因畫面重建或行程終止導致的錯誤或狀態遺失;改用 rememberSaveable 保留文字欄位內容;導航上以 popUpTo 清除認證圖中的返回堆疊,並建立一個 DRY 的設定更新函式。接下來的 v1.2.0 專注於離線同步、零延遲計時器、搜尋去抖與列表優化,以及將分析運算移離主線程,提升效能與 UX。

03

I Thought val Meant Immutable. I Was Half Right.

Medium Kotlin 作者:Kisna Lunagariya 發布:03-22 07:10

我以為 val 是不可變的。我是半對的。

文章從「什麼是 val、什麼是 var」出發,說明 val 代表不可重新指派的參考,但不保證被指向物件的深層不可變性。

重點摘要

說明 val 與 var 的差異
釐清 val 是不可重新指派的參考,而非物件狀態的絕對不可變
建議使用不可變型別或防護性複製以確保真正的不可變性

本文從「什麼是 val、什麼是 var」出發,說明 Kotlin 中 val 表示不可重新指派的參考(read-only reference),但不等同於物件的深層不可變性。作者區分了參考不可變與物件狀態不可變的差異:val 無法讓變數名稱指向另一個物件,但被指向的物件若提供可變操作仍可改變內部狀態。實務上,val 有助於避免意外改指,但若要保證真正不可變,仍需設計或使用不可變型別、或採取防護性複製等策略。文章旨在糾正常見誤解:對 val 的理解是「有半對」——參考層面不可變,物件層面不一定。

04

I Built a Better Result Type for Kotlin

Medium Kotlin 作者:J Kolev 發布:03-22 08:26

我為 Kotlin 建立了一個更好的 Result 類型

有時最好的學習方式,就是自己動手去做。

重點摘要

作者為 Kotlin 實作了自訂的 Result 類型
以實作為導向的學習方法為主軸
說明設計動機、實作取捨與實務經驗

J Kolev 在這篇 Medium 文章中說明他如何透過實作來建立一個更好的 Kotlin Result 類型。文章強調以動手做為學習手段,說明為何需要替代標準 Result、在實作過程中的設計選擇,以及這些選擇對使用方式的影響。作者以專案示例說明不同取捨、實務設計模式與學到的經驗,適合對錯誤處理型別有興趣或偏好透過實作學習的 Kotlin 開發者閱讀,提供理論與可實作的見解。

05

From Login to Logout: Simple Session Management in Android using SharedPreferences

Medium Kotlin 作者:Animesh 發布:03-22 09:06

從登入到登出:使用 SharedPreferences 在 Android 上實作簡易會話管理

當應用直接帶你到主畫面而不再要求登入時,這就是透過裝置上的會話管理實現的行為。

重點摘要

以 SharedPreferences 儲存登入狀態或使用者識別
啟動應用時檢查會話狀態以導向主畫面或登入畫面
登出時清除偏好設定以終止會話

本文示範如何在 Android 中使用 SharedPreferences 實作簡單的會話管理。說明以 SharedPreferences 作為輕量的鍵值儲存,保存登入狀態(或簡易識別資訊),使應用重啟後能判斷並直接進入主畫面或顯示登入畫面;登出時則清除偏好設定來結束會話。文中強調此法實作簡單、程式碼精簡,但 SharedPreferences 適合非敏感資料,若需儲存敏感認證應採用更安全的方案。整體提供一個從登入到登出的實用範例與流程。

06

Architecting Shredzilla: Surviving Process Death and Slaying Memory Leaks in Jetpack Compose

Medium Kotlin 作者:freerave 發布:03-22 09:15

Architecting Shredzilla:在 Jetpack Compose 中存活進程終止並消滅記憶體洩漏

用 Jetpack Compose 打造漂亮介面令人滿足,但要建立能在 Android 進程終止後仍能存活並避免記憶體洩漏的架構才是真挑戰。

重點摘要

為 Android 進程終止設計復原能力
偵測並預防 Compose 應用的記憶體洩漏
採用適合 Compose 的狀態恢復與清理模式

文章探討如何為 Jetpack Compose 應用設計架構,使其能在 Android 進程被系統終止後正確復原,並同時降低或消除記憶體洩漏的風險。作者提出關鍵原則,包括穩健的狀態恢復、生命週期感知的元件、資源正確範圍與清理、以及避免持有 UI 參考等,並建議採用與 Compose 相容的範式來保存必要狀態與安全地處理副作用。此外還涵蓋偵測與測試進程重啟情境的實務技巧,旨在提供工程師可操作的指引,提升應用在真實生命週期事件下的穩定性與記憶體安全。

07

Java vs Kotlin vs Scala: Which to Choose in 2026

Medium Kotlin 作者:Furkan Alnıak 發布:03-22 10:01

Java vs Kotlin vs Scala:2026 年該如何選擇

比較 Java、Kotlin 與 Scala 的優勢、限制與適用場景,並以三種語言的程式範例與示範專案呈現實務差異。

重點摘要

評估各語言的優勢、限制與適用情境。
提供三種語言的並排程式範例以示差異。
附上以三種語言實作的示範專案以利實作比較。

Furkan Alnıak 的文章比較 Java、Kotlin 與 Scala,為 2026 年的語言選擇提供實務導向的參考。作者檢視各語言的優勢與限制,包括語法簡潔性、函式式特性、JVM 互操作性、生態系與工具成熟度與學習曲線,並未指定單一最佳選擇。文章同時提供三種語言的對照程式範例與一個示範專案,讓讀者直接觀察風格、冗長度與慣用法的差異。結論上建議依專案需求取捨:重穩定與廣泛支援可選 Java、追求現代簡潔與 Android 整合可選 Kotlin、需要高階函式與強型別表現則可考慮 Scala。

08

Mastering Jetpack Compose Side Effects: Fixing the Stale Lambda Problem

Medium Kotlin 作者:Sivavishnu 發布:03-22 14:37

掌握 Jetpack Compose 的副作用:修正陳舊的 Lambda 問題

為何副作用會使用過時資料,以及如何銜接重組與協程的生命週期。

重點摘要

副作用可能在重組後仍使用舊有資料或 lambda
重組與協程生命週期不一致會導致陳舊的執行內容
應將協程生命週期與組件重組銜接,確保副作用使用最新狀態

本文說明 Jetpack Compose 中常見的「陳舊 lambda」問題:當 UI 發生重組時,系統會產生新的 lambda 或狀態,但已啟動的副作用(例如協程)可能仍持有並執行舊的參考,導致使用過時資料。問題核心在於重組的生命週期與協程生命週期不一致,會產生難以察覺的錯誤。文章指出如何偵測副作用在使用過時資料,並提出一般性策略:讓副作用觀察並使用當前狀態、將協程生命週期與組合綁定以在輸入改變時取消並重啟,以及使用會更新的參考或回呼。採用這些做法可以使非同步副作用在重組間保持可預期與正確。

09

Dependency Injection on Mobile: Swinject (iOS) vs Dagger Hilt (Android)

Medium Kotlin 作者:tahn98 發布:03-22 04:24

行動平台的依賴注入:Swinject(iOS)與 Dagger Hilt(Android)比較

針對行動開發者的入門且深入指南,說明依賴注入在 iOS 與 Android 的運作與差異。

重點摘要

說明依賴注入的核心概念與重要性
比較 Swinject(iOS)與 Dagger Hilt(Android)的作法
提供選擇與應用 DI 的實務建議

本文為針對行動開發者的入門且深入指南,說明依賴注入(Dependency Injection)在 iOS(以 Swinject 為例)與 Android(以 Dagger Hilt 為例)上的運作。文章先介紹 DI 的核心概念與其在模組化、測試性及資源/生命週期管理上的重要性,再比較兩者在設置流程、與平台生命週期整合與常見使用模式的差異與取捨。內容適合初學者,釐清專有名詞、指出常見陷阱,並提供選擇與應用 DI 的實務建議,幫助讀者在 iOS 與 Android 專案中建立可維護且易於測試的依賴架構。