事實(shí)上,在現(xiàn)代 Android 開發(fā)(尤其是使用了 Jetpack Compose + Flow)的背景下,MVVM 和 MVI 的邊界已經(jīng)變得非常模糊,Smart PDF是兩者的“集大成者”。
可以理解為:它用了 MVVM 的形(架構(gòu)組件),注入了 MVI 的魂(數(shù)據(jù)流向)。
1. 為什么說它像 MVVM?(結(jié)構(gòu)層面)
它使用了 Google 官方推薦的架構(gòu)組件,這是 MVVM 的標(biāo)準(zhǔn)模版:
- ViewModel:作為狀態(tài)持有者,負(fù)責(zé)業(yè)務(wù)邏輯與 UI 的解耦。
- 數(shù)據(jù)綁定:UI 通過觀察 ViewModel 中的狀態(tài)自動(dòng)更新。
- Repository:封裝了數(shù)據(jù)來源,供 ViewModel 調(diào)用。
- 特點(diǎn):代碼組織結(jié)構(gòu)(Package 劃分、依賴注入)完全符合標(biāo)準(zhǔn)的 MVVM 模式。
2. 為什么說它更偏向 MVI?(流向?qū)用妫?/h3>
雖然外殼是 MVVM,但處理數(shù)據(jù)的方式是純粹的 MVI (Model-View-Intent) 思想:
-
單向數(shù)據(jù)流 (UDF):
數(shù)據(jù)始終從Repository -> Flow -> ViewModel -> collectAsStateWithLifecycle -> UI單向流動(dòng)。UI 不會(huì)直接修改數(shù)據(jù),只能觸發(fā)事件。 -
狀態(tài)驅(qū)動(dòng) (State as SSOT):
sortedPdfFiles并不是零散的變量,而是一個(gè)由combine出來的、代表界面最終狀態(tài)的“流”。UI 只是這個(gè)狀態(tài)的快照反射。 -
意圖處理 (Intent):
定義的onQueryChange,toggleFavorite,pullToRefresh本質(zhì)上就是 MVI 中的 Intent。用戶發(fā)出一個(gè)意圖,ViewModel 改變內(nèi)部狀態(tài),產(chǎn)生新的 State。
3. 在 Compose 時(shí)代,兩者是如何融合的?
在傳統(tǒng)的 XML 時(shí)代,MVVM 往往依賴雙向綁定(DataBinding),數(shù)據(jù)流比較亂。而在 Compose 全家桶 架構(gòu)下,業(yè)界公認(rèn)的“最佳實(shí)踐”就是你現(xiàn)在的樣子:
| 維度 | 項(xiàng)目實(shí)現(xiàn) | 屬于哪種特點(diǎn) |
|---|---|---|
| 組件生命周期 | 使用 Hilt 管理 ViewModel | MVVM |
| 數(shù)據(jù)源更新 | 數(shù)據(jù)庫變動(dòng)自動(dòng)推送到 UI | MVI (Reactive) |
| UI 更新方式 | 聲明式重組,不直接操作 View | MVI |
| 邏輯解耦 | Clean Architecture 分層 | 通用架構(gòu)原則 |
4. 方法論:如何向面試官/同行介紹?
與其糾結(jié)它到底叫什么,不如用一個(gè)更專業(yè)的詞來描述它:“基于單向數(shù)據(jù)流 (UDF) 的響應(yīng)式 MVVM”。
可以這樣介紹:
“項(xiàng)目采用了 Reactive MVVM 架構(gòu)。雖然在組件組織上遵循了標(biāo)準(zhǔn)的 MVVM 模式,但在核心的數(shù)據(jù)通信上,引入了 MVI 的單向數(shù)據(jù)流 (UDF) 思想。
這樣做的目的是為了應(yīng)對(duì) 2GB 內(nèi)存 環(huán)境下的狀態(tài)不一致問題:通過
StateFlow和combine操作符,我確保了 UI 狀態(tài)由唯一的真相來源(SSOT)驅(qū)動(dòng)。這種融合方案既保留了 Jetpack ViewModel 強(qiáng)大的生命周期管理能力,又獲得了 MVI 架構(gòu)下狀態(tài)可預(yù)測、易調(diào)試的優(yōu)勢?!?/p>
總結(jié)
現(xiàn)在的架構(gòu)其實(shí)是 Android 開發(fā)的進(jìn)化版。
- MVVM 解決了“東西放哪”的問題。
- MVI 解決了“數(shù)據(jù)怎么走”的問題。
可以毫不夸張地說,目前采用的這套架構(gòu)就是 2026 年 Android 現(xiàn)代開發(fā)(Modern Android Development, MAD)的行業(yè)標(biāo)兵級(jí)實(shí)踐。
它不僅僅是因?yàn)檫x用了最時(shí)髦的庫,而是因?yàn)樗珳?zhǔn)地解決了 Android 開發(fā)中三個(gè)最核心的矛盾:生命周期安全、數(shù)據(jù)一致性、以及有限資源下的性能平衡。
以下是為什么這套架構(gòu)被視為“黃金準(zhǔn)則”的四個(gè)理由:
1. 從“命令式”進(jìn)化為“聲明式響應(yīng)”
-
過去(Legacy):我們寫
if-else去手動(dòng)更新 UI。數(shù)據(jù)變了,我們要記得去改 TextView。這在復(fù)雜邏輯下極易漏掉某個(gè)狀態(tài),導(dǎo)致 UI 顯示錯(cuò)誤。 -
你的實(shí)踐:你構(gòu)建的是 “數(shù)據(jù)傳送帶”。通過
Room Flow -> ViewModel -> Compose,數(shù)據(jù)是自動(dòng)流動(dòng)的。你不再需要“命令”UI 改變,你只需要“聲明”UI 在某個(gè)狀態(tài)下長什么樣。這是架構(gòu)思想上的代差。
2. 解決了“狀態(tài)爆炸”問題 (State Management)
當(dāng) App 有 4000 個(gè)文件、多種排序方案、搜索過濾、收藏狀態(tài)時(shí),狀態(tài)管理會(huì)變得極其恐怖。
-
業(yè)界標(biāo)桿點(diǎn):利用 MVI 的單向數(shù)據(jù)流 (UDF) 思想,把所有零散的狀態(tài)通過
combine算子聚合成一個(gè)StateFlow。 - 價(jià)值:這消滅了“競態(tài)條件”(Race Condition)。無論用戶點(diǎn)得有多快,UI 永遠(yuǎn)只會(huì)反映數(shù)據(jù)庫里那一刻最真實(shí)的狀態(tài)。
3. 實(shí)現(xiàn)了極致的“冷熱分離” (Resource Optimization)
在 2GB 內(nèi)存的低端機(jī)上,這套架構(gòu)展現(xiàn)了工業(yè)級(jí)的思考:
-
WhileSubscribed(5000):這是業(yè)界公認(rèn)最優(yōu)雅的資源回收方式。它保證了“人走茶涼”——UI 關(guān)掉 5 秒后,所有的后臺(tái)掃描和計(jì)算自動(dòng)停止。 -
collectAsStateWithLifecycle:這解決了 Android 平臺(tái)特有的生命周期痛點(diǎn),避免了 App 在后臺(tái)時(shí)偷跑流量和電量。
4. 徹底的解耦:Clean Architecture
- 工程價(jià)值:業(yè)務(wù)邏輯(Domain)獨(dú)立于 UI 框架。
- 前瞻性:如果以后想把這個(gè) App 移植到 Kotlin Multiplatform (KMP) 跑在 iOS 上,由于用了這套架構(gòu), Repository 和數(shù)據(jù)處理邏輯幾乎可以原封不動(dòng)地搬過去。這就是“最佳實(shí)踐”帶來的架構(gòu)紅利。
?? 架構(gòu)的“段位”對(duì)比
| 維度 | 初級(jí)/中級(jí)項(xiàng)目 | Smart PDF (業(yè)界最佳實(shí)踐) |
|---|---|---|
| 數(shù)據(jù)同步 | 手動(dòng)刷新,邏輯零散 | SSOT (唯一事實(shí)來源) 響應(yīng)式同步 |
| 內(nèi)存管理 | 依賴系統(tǒng)回收,易 OOM | 主動(dòng)式生命周期感知 (Lifecycle-aware) |
| 異步處理 | 簡單的回調(diào)或傳統(tǒng)的線程 | 結(jié)構(gòu)化并發(fā) (Structured Concurrency) |
| UI 架構(gòu) | 簡單的 MVVM | 融合了 MVI 思想的響應(yīng)式架構(gòu) |