一、UI 架構(gòu)的定義
UI 系統(tǒng)的作用是把“用戶操作和數(shù)據(jù)變化”映射為“界面變化”。
從輸入(Action+data)到輸出(UI)包含了諸多工作,比如有:
- 事件分發(fā)與意圖解析
- 數(shù)據(jù)獲取與聚合
- 業(yè)務(wù)邏輯處理
- 界面渲染
...等等
我們進行架構(gòu)設(shè)計就是去:
- 確定設(shè)立哪些功能模塊;
- 確定每一項工作交給哪個模塊負責;
- 確定各個模塊之間的依賴關(guān)系和通信方式;
用一句話總結(jié)
UI架構(gòu)就是UI系統(tǒng)中各模塊職責劃分、依賴關(guān)系以及數(shù)據(jù)流轉(zhuǎn)方式的整體設(shè)計。
UI 架構(gòu)解決的問題是—如何把“用戶意圖(操作)和數(shù)據(jù)變化”高效、穩(wěn)定地映射為“界面變化”。
UI 架構(gòu)的演化本質(zhì)上是為了應(yīng)對不斷增長的復(fù)雜度。
當“數(shù)據(jù)變化”越來越頻繁、“用戶交互”越來越復(fù)雜時,采用原有架構(gòu):
- 開發(fā)成本和難度不斷上升;
- 系統(tǒng)運行時候的穩(wěn)定性和效率不斷下降;
于是架構(gòu)不斷演進——
二、UI 架構(gòu)演化五階段
?? 第一階段:無架構(gòu) / 混沌階段
?? 核心思想
對每個UI 組件,逐個編碼操作。
整個業(yè)務(wù)流程+UI操作在代碼層是混合在一起的,具體每個業(yè)務(wù)需要操作哪些UI這些都是程序員的腦子在記憶。
textview = findView(R.id.tv)
textView.setText("Hello");
? 優(yōu)勢
- 簡單直接
- 易于上手
- 微小項目開發(fā)效率高
? 問題
數(shù)據(jù)和界面強耦合:當一個數(shù)據(jù)變化,關(guān)聯(lián)頁面很多,要手動更新五六個按鈕,極其容易漏掉,導(dǎo)致“顯示不一致。
多人協(xié)作容易混亂
業(yè)務(wù)邏輯不可復(fù)用
?? 演化契機
項目變大,代碼亂到無法維護時候,開發(fā)者開始意識到—UI 和邏輯不能混作一團,于是引入分層思想。
?? 第二階段:分層架構(gòu)(MVC / MVP)
?? 核心思想
UI 和邏輯要分離
- Model:數(shù)據(jù)
- View:界面
- Presenter / Controller:邏輯
? 優(yōu)勢
- 解耦 UI 和業(yè)務(wù)邏輯
- 提升可維護性
- 更適合團隊開發(fā)
? 問題
- 接口爆炸(IView、IPresenter)
- 各個模塊相互引用,內(nèi)存泄漏風險高
- 雙向調(diào)用,數(shù)據(jù)流混亂
?? 演化契機
開發(fā)者逐漸意識到:
問題不在“分層”,而在決定UI的因素沒有被顯式建模和統(tǒng)一管理,
例如
- 加載中?還是加載失???還是加載成功?
- 用戶點過按鈕了嗎?
- 當前展示的是舊數(shù)據(jù)還是新數(shù)據(jù)?
- 多個請求回來,哪個是“最終結(jié)果”
...等等
這些控制UI的因素是隱式地分散在 UI 容器、業(yè)務(wù)邏輯、數(shù)據(jù)層、異步流程以及用戶交互等多個維度中,系統(tǒng)缺乏統(tǒng)一的ui更新因素輸入源,從而引發(fā)復(fù)雜性和大量不可預(yù)測問題。
這就好比:一個基層執(zhí)行人員每天的工作是由公司幾十個領(lǐng)導(dǎo)指派,那就很容易出現(xiàn)各種問題,比如任務(wù)前后矛盾,任務(wù)過載堵塞等。
?? 第三階段:狀態(tài)驅(qū)動(MVVM)
?? 核心思想
- 引入狀態(tài)概念:狀態(tài) = 在某一時刻,完整決定 UI 長什么樣的最小信息集合。
- 狀態(tài)被顯性建模,并指出:UI = f(State)
public class MyViewModel(
// 狀態(tài)定義Start
public MutableLiveData<Boolean> isLoadingLiveData = new MutableLiveData<>();
public MutableLiveData<List<Item>> showListLivaData = new MutableLiveData<>();
public MutableLiveData<String> errorLiveData = new MutableLiveData<>();
// 狀態(tài)定義End
)
從此UI 的顯示邏輯由 state 統(tǒng)一控制推導(dǎo),而不是分散在各處手動操作。
? 優(yōu)勢
- 狀態(tài)被顯式建模
- UI 變成“可推導(dǎo)”的
- 更容易測試和維護
? 問題
- 狀態(tài)可能出現(xiàn)非法組合:因為一個頁面狀態(tài)可以是“碎片化”的,它們之間沒有建立“關(guān)系約束”;
- 狀態(tài)變化沒有約束,會出現(xiàn)從狀態(tài)A變化到一個錯誤狀態(tài)C的問題;
- UI 更新仍然是手動同步:手工寫如何根據(jù)狀態(tài)怎么更新UI的操作。
?? 演化契機
開發(fā)者進一步思考:
當狀態(tài)變量多了,無統(tǒng)一管理,容易出現(xiàn)非法狀態(tài)——狀態(tài)整合
狀態(tài)量碎片化,導(dǎo)致狀態(tài)變化難以約束,狀態(tài)轉(zhuǎn)換頻頻出錯——狀態(tài)切換約束(狀態(tài)機)
?? 第四階段:單向數(shù)據(jù)流(MVI / Redux)
?? 核心思想
狀態(tài)整合
狀態(tài)變化必須可追蹤、可推導(dǎo)
State??? = Reduce(State?, Action)
?? 本質(zhì)是一個:狀態(tài)機
這一階段的本質(zhì)升級:
從:
“狀態(tài)存在”
變成:
狀態(tài)成為一個原子整體
狀態(tài)如何變化也被建模
把“狀態(tài)變化過程”徹底規(guī)范化
? 優(yōu)勢
- 狀態(tài)變化可預(yù)測
- 易于調(diào)試(可回放)
- 消滅“非法狀態(tài)組合”
? 問題
- UI 仍然需要手動更新
- 模板代碼較多
- 開發(fā)學習難度高
?? 演化契機
開發(fā)者發(fā)現(xiàn):
狀態(tài)管理已經(jīng)很不錯,但 是從狀態(tài)到UI的映射仍然是“手動同步”的
?? 第五階段:聲明式 UI(React / Compose)
代表:Jetpack Compose
?? 核心思想
UI = f(state)
之前階段 :UI = “如何從 A 變到 B”,在這個階段變?yōu)椤爱斍皯?yīng)該是什么樣”
- 之前階段:關(guān)注“過程”
- 第5階段:關(guān)注“結(jié)果”
? 傳統(tǒng) UI 的本質(zhì)
UI 是“可變對象”
你在做不斷修改它
? 聲明式UI的本質(zhì)
UI 是“計算結(jié)果”
你在做:每次重新算一個新的 UI
聲明式 UI 不是“控制 UI 的變化”而是“不斷給出 UI 的完整定義”,未被聲明的部分不會存在。
示例
@Composable
fun ListScreen(state: UiState) {
when (state) {
is Loading -> LoadingView()
is Success -> ListView(state.data)
is Error -> ErrorView()
}
}
第一次狀態(tài)更新:Loading 狀態(tài)
when (state) {
is Loading -> LoadingView()
}
?? UI 樹:
Root
└── LoadingView
狀態(tài)變成 Success
when (state) {
is Success -> ListView()
}
?? 新 UI 樹:
Root
└── ListView
?? 關(guān)鍵發(fā)生了什么?
Compose 在內(nèi)部做了這件事:
舊樹: LoadingView
新樹: ListView
→ diff
→ 刪除 LoadingView
→ 添加 ListView
?重點來了
?? 你沒有寫:
hide(LoadingView)
?? 但系統(tǒng)幫你做了:
從 UI 樹中移除
?? 這就是“聲明式”的真正含義
? 傳統(tǒng)命令式UI
你:把 LoadingView 隱藏
? 聲明式
你更新State,Loading is false
?? 系統(tǒng)推導(dǎo)出:現(xiàn)在 UI 不應(yīng)該有 LoadingView,
那就刪掉LoadingView
? 優(yōu)勢
- UI 自動與狀態(tài)一致
- 不再需要手動同步
- 消滅 UI 狀態(tài)錯亂
- 更接近函數(shù)式編程
? 問題
- 狀態(tài)設(shè)計難度上升(核心問題轉(zhuǎn)移)
- 副作用管理復(fù)雜(除了更新 UI State 以外,所有會對外界產(chǎn)生影響的操作,都是副作用,比如Toast、讀寫數(shù)據(jù)庫、修改全局變量、打日志等)
- 學習成本較高
- 容易寫出“偽聲明式代碼”
?? 演化契機
問題再次升級:
?UI 已經(jīng)很好,但狀態(tài)建模成為瓶頸
三、傳統(tǒng)UI架構(gòu)演化的終極目標
從整個歷史來看,UI 架構(gòu)一直在逼近一個目標:
?? 終極形態(tài)
UI = f(State)
State = g(UserIntent, Data)
?? 核心特征
- UI 完全由狀態(tài)決定
- 狀態(tài)變化可預(yù)測
- 無副作用污染(狀態(tài)更新時候只更新 UI State ,不會有對外界產(chǎn)生影響的其他操作)
- 系統(tǒng)自動完成更新
?? 用一句話總結(jié):
當 UI 完全由狀態(tài)決定,狀態(tài)變化完全由可追蹤的行為驅(qū)動時,系統(tǒng)就從“不可控的黑箱”,變成了一個“可以被理解、被推演、甚至被回放的白箱系統(tǒng)”——這正是 傳統(tǒng)UI 架構(gòu)演化的終點。
但現(xiàn)在AI來了,一切又不一樣了
四、AI時代的演化方向
開發(fā)者不想再“手寫狀態(tài)機”
MVI / Redux 本質(zhì)是:
?? 人類在手動維護一個“狀態(tài)機”
但問題是:
- 狀態(tài)爆炸(State explosion)
- 分支復(fù)雜(if / else 地獄)
- 維護成本極高
?? 本質(zhì):
? 人在“模擬智能”,但人并不擅長這個
AI(尤其是大模型)帶來了一個非常關(guān)鍵的能力:
?? 從“規(guī)則驅(qū)動”變成“意圖驅(qū)動”
過去:
用戶點擊 → Action → reducer → State → UI
現(xiàn)在開始變成:
用戶表達 → AI理解(Intent) → 生成狀態(tài) / UI → 渲染
?? 關(guān)鍵變化:
“狀態(tài)不再完全由人定義,而是可以被推導(dǎo) / 生成”
過去:
Human: 定義 State + Transition
現(xiàn)在:
AI: 推導(dǎo) State
Human: 定義約束(Constraint)
?? 核心變化不是“AI生成UI”
而是:
人從“構(gòu)造狀態(tài)機”,變成“約束狀態(tài)空間”
如果說過去的 UI 架構(gòu)是在解決“如何讓狀態(tài)不失控”,那么未來的 UI 架構(gòu),將是在解決——當狀態(tài)本身由機器生成時,人類如何依然掌控系統(tǒng)的邊界。