1 背景介紹
1.1 宣告式ui
宣告式UI其實并不是近幾年的新技術,但是近幾年宣告式UI框架非常的火熱,單說移動端,跨平臺方案有:RN、Flutter,iOS原生有:SwiftUI,android原生有:compose,可以看到宣告式UI是以后的前端發展趨勢,而狀態管理是宣告式UI框架的重要組成部分,
1.2 宣告式UI框架的狀態
在移動端之前的命令式UI框架,沒有狀態的概念,每個控制元件其實都是無狀態的,我們要更新UI需要手動的去set,命令式UI引入狀態的概念,狀態可以理解為訂閱了控制元件所依賴資料的變化,當一個控制元件依賴的資料發生變化時,自動重繪UI展示,最大的優勢就是可以很方便的做到UI和邏輯的解耦,
2 provider狀態管理
2.1 使用方式
定義一個頁面如下:
實作功能,當點擊“按鈕”的時候,更新“你好”這個組件
頁面部分代碼實作(基于StatelessWidget實作):
model部分實作:
2.2 問題和不足
點擊“按鈕”的時候查看頁面重繪,發現下表羅列的Widget都執行了重繪操作,使用Selector雖然被包裹的內容沒有重繪,但是需要進行校驗操作,
2.2.1 控制元件重繪
2.2.2 問題分析
- 使用不太靈活,想要消費事件重繪UI必須有頂層的Provider提供model,在一些復雜場景可能會增加邏輯復雜度
- 狀態重繪,不能實作最小粒度的管理
- 代碼不夠簡潔
3 新的狀態管理方式實踐
3.1 使用方式
實作同樣的上述頁面邏輯,代碼如下(同樣基于StatelessWidget實作):
首先不需要依賴外部的provider提供Model,任何想要獨立重繪的區域使用TosObWidget控制元件包裹即可,使用比較靈活,我們可以把TosObWidget插入到任何我們想要的位置(包括provider內),代碼邏輯比較簡潔
model實作:
model的實作更加簡潔,不需要繼承ChangeNotifier,所以可以把狀態資料定義在任何我們想要的地方,使用.tos擴展屬性回傳一個包含默認值的RxObj物件,當我們使用set方法更改RxObj的value的時候,通知依賴此物件的TosObWidget區域進行重繪,例:我們點擊按鈕的時候,_model.textA.value = https://www.cnblogs.com/Jcloud/archive/2023/06/20/“你好${_model.i++}”,執行后就會重繪依賴textA的TosObWidget(() => Text(_model.textA.value))區域
查看重繪狀態(與provider對比):
對比發現TosObWidget這種方式,只有依賴的資料發生變化的TosObWidget才會更新狀態,可以實作狀態重繪粒度最小化,提高性能
3.2 設計思路
3.2.1 TosObWidget
首先是使用入口,定義一個TosObWidget控制元件,入參為build函式,回傳widget,每個TosObWidget就是一個可獨立進行狀態重繪的區域
TosObWidget控制元件的實作如下:
TosObWidget的build函式為多載的其父類_ObzWidget的build函式,最侄訓被_ObzWidget的_ObzState呼叫,_ObzWidget的實作如下:
接下來查看_ObzState的實作,主要邏輯都在這個類進行實作,這里貼出所有的代碼(注意框起來的邏輯):
3.2.2 TosObWidget邏輯分析
- 首先_ObzState依賴一個RxObserver _observer變數
- RxObserver _observer這個 變數持有了_updateUI()這個方法,最侄訓通過這個方法重繪TosOBWidget的狀態
- 當TosObWidget執行build的時候,會通過一個靜態變數RxObserver.proxy把_observer共享出去
- 這樣TosObWidget包裹的內容,使用RxObj的getValue的時候會拿到被共享的_observer,這時建立RxObj和TosObWidget的聯系
- 聯系建立后,重置共享變數RxObserver.proxy
- 這樣在RxObj的value執行set方法時,會呼叫到與其系結的TosObWidget的_updateUI()這個函式
3.2.3 RxObj的實作
如下貼出RxObj的value的get和set函式:
- 當執行RxObj的value的get方法時,代碼如下,拿到 RxObserver的靜態成員變數proxy,型別為RxObserver(即為上一步TosObWidget共享出來的_observer)
- 判斷RxObserver.proxy不為空,且沒有被添加到_observers串列( List _observers),則添加
- 當執行RxObj的value的set方法時,校驗value是否與當前的value值相同,且判斷是否是首次創建(首次創建不會執行狀態重繪)
- 校驗完成后則賦值執行refresh()函式,更新TosObWidget的狀態
refresh()函式的實作如下:
observer.update()函式即為執行與Rxobj關聯的TosObWidget的_updateUI()函式:
看下RxObserver的實作:
注意框起來的邏輯,update函式即上面_ObzState的_updateUI()函式的參考
至此整個實作流程已經貫通了,接下來看下如何使用:
1)通過.tos擴展屬性定義RxObj變數:
2).tos擴展屬性的實作如下:
3)如果要創建一個默認值為空的,RxObj實體,使用如下方式:
此時如果我們使用RxObj的setValue方法,就會重繪依賴它的所有TosObWidget控制元件,如果有些情況下,沒有呼叫setValue方法,但是需要重繪狀態,可手動呼叫refresh()方法,實作如下:
至此,就完成了TosObWidget控制元件的狀態重繪
4 總結
注:基于本文示例的功能邏輯進行對比
作者:京東物流 張俊飛
來源:京東云開發者社區
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/555731.html
標籤:其他
上一篇:Android Studio中SQLite的使用,主要介紹sqlite插入和讀出圖片(ViewBinder)的操作方法
下一篇:返回列表