Flutter Riverpod 全面深入解析告希,為什么官方推薦它扑浸?

隨著 Flutter 的發(fā)展,這些年 Flutter 上的狀態(tài)管理框架如“雨后春筍”般層出不窮燕偶,而近一年以來(lái)最受官方推薦的狀態(tài)管理框架無(wú)疑就是 Riverpod 喝噪,甚至已經(jīng)超過(guò)了 Provider ,事實(shí)上 Riverpod 官方也稱自己為 “Provider指么,但與眾不同”酝惧。

Provider 本身用它自己的話來(lái)說(shuō)是 “InheritedWidget 的封裝,但更簡(jiǎn)單且復(fù)用能力更強(qiáng)伯诬⊥泶剑” ,而 Riverpod 就是在 Provider 的基礎(chǔ)上重構(gòu)了新的可能盗似。

關(guān)于過(guò)去一年?duì)顟B(tài)管理框架的對(duì)比可以看 《2021 年的 Flutter 狀態(tài)管理:如何選擇哩陕?》本文主要是帶你解剖 RiverPod 的內(nèi)部是如何實(shí)現(xiàn)赫舒,理解它的工作原理悍及,以及如何做到比 Provider 更少的模板和不依賴 BuildContext

前言

如果說(shuō) Riverpod 最明顯的特點(diǎn)是什么接癌,那就是外部不依賴 BuildContext (其實(shí)就是換了另外一種依賴形態(tài))并鸵,因?yàn)椴灰蕾?BuildContext ,所以它可以比較簡(jiǎn)單做到類似如下的效果:

也就是 Riverpod 中的 Provider 可以隨意寫成全局扔涧,并且不依賴 BuildContext 來(lái)編寫我們需要的業(yè)務(wù)邏輯园担。

?? 提前聲明下,這里和后續(xù)的 Provider 枯夜,和第三方庫(kù) provider 沒(méi)有關(guān)系弯汰。

Riverpod 具體內(nèi)部是怎么實(shí)現(xiàn)的呢?接下來(lái)讓我們開(kāi)始探索 Riverpod 的實(shí)現(xiàn)原理湖雹。

Riverpod 的實(shí)現(xiàn)相對(duì)還是比較復(fù)雜咏闪,所以還耐心往下看,因?yàn)楸酒侵鸩浇馕觯?strong>所以如果看的過(guò)程有些迷惑可以先不必在意摔吏,通篇看完再回過(guò)來(lái)翻閱可能就會(huì)更加明朗鸽嫂。

從 ProviderScope 開(kāi)始

在 Flutter 里只要使用了狀態(tài)管理纵装,就一定避不開(kāi) InheritedWidget , Riverpod 里也一樣据某,在 Riverpod 都會(huì)有一個(gè) ProviderScope橡娄, 一般只需要注冊(cè)一個(gè)頂級(jí)的 ProviderScope

如果對(duì)于 InheritedWidget 還有疑問(wèn)癣籽,可以看我掘金:《全面理解State與Provider》

先從一個(gè)例子開(kāi)始挽唉,如下圖所示,是官方的一個(gè)簡(jiǎn)單的例子筷狼,可以看到這里:

  • 嵌套一個(gè)頂級(jí) ProviderScope 瓶籽;
  • 創(chuàng)建了一個(gè)全局的 StateProvider
  • 使用 ConsumerWidgetref 對(duì)創(chuàng)建的 counterProvider 進(jìn)行 read 從而讀取 State 埂材,獲取到 int 值進(jìn)行增加 塑顺;
  • 使用另一個(gè) Consumerref 對(duì)創(chuàng)建的 counterProvider 進(jìn)行 watch ,從而讀取到每次改變后的 int 值俏险;

很簡(jiǎn)單的例子严拒,可以看到?jīng)]有任何 of(context) , 而全局的 counterProvider 里的數(shù)據(jù)寡喝,就可以通過(guò) ref 進(jìn)行 read/watch糙俗,并且正確地讀取和更新。

那這是怎么實(shí)現(xiàn)的呢预鬓?counterProvider 又是如何被注入到 ProviderScope 里面巧骚?為什么沒(méi)有看到 context? 帶著這些疑問(wèn)我們繼續(xù)往下探索格二。

首先我們看 ProviderScope 劈彪,它是唯一的頂級(jí) InheritedWidget ,所以 counterProvider 必定是被存放在這里:

在 RiverPod 里顶猜, ProviderScope 最大的作用就是提供一個(gè) ProviderContainer 沧奴。

更具體地說(shuō),就是通過(guò)內(nèi)部嵌套的 UncontrolledProviderScope 提供长窄,所以到這里我們可以知道:ProviderScope 可以往下提供狀態(tài)共享滔吠,因?yàn)樗鼉?nèi)部有一個(gè) InheritedWidget ,而主要往下共享的是 ProviderContainer 這個(gè)類挠日。

所以首先可以猜測(cè):我們定義的各種 Providers疮绷, 比如上面的 counterProvider , 都是被存到 ProviderContainer 中嚣潜,然后往下共享冬骚。

事實(shí)上官方對(duì)于 ProviderContainer 的定義就是:用于保存各種 Providers 的 State ,并且支持 override 一些特殊 Providers 的行為

ProviderContainer

這里出現(xiàn)了一個(gè)新的類只冻,叫 ProviderContainer 庇麦,其實(shí)一般情況下使用 RiverPod 你都不需要知道它,因?yàn)槟悴粫?huì)直接操作和使用它喜德,但是你使用 RiverPod 的每個(gè)行為都會(huì)涉及到它的實(shí)現(xiàn)山橄,例如 :

  • ref.read 會(huì)需要它的 Result read<Result>
  • ref.watch 會(huì)需要它的 ProviderSubscription<State> listen<State> 住诸;
  • ref.refresh 會(huì)需要它的 Created refresh<Created>

就算是各種 Provider 的保存和讀取基本也和它有關(guān)系驾胆,所以它作為一個(gè)對(duì)各種 Provider 的內(nèi)部管理的類涣澡,實(shí)現(xiàn)了 RiverPod 里很關(guān)鍵的一些邏輯贱呐。

“Provider” 和 “Element”

那前面我們知道 ProviderScope 往下共享了 ProviderContainer 之后,Provider 又是怎么工作的呢入桂?為什么 ref.watch/ ref.read 會(huì)可以讀取到它 Provider 里的值奄薇?

繼續(xù)前面的代碼,這里只是定義了 StateProvider 抗愁,并且使用了 ref.watch 馁蒂,為什么就可以讀取到里面的 state 值?

首先 StateProvider 是一個(gè)特殊的 Provider 蜘腌,在它的內(nèi)部還有一個(gè)叫 _NotifierProvider 的幫它實(shí)現(xiàn)了一層轉(zhuǎn)換沫屡,所以我們先用最基礎(chǔ)的 Provider 類作為分析對(duì)象

基本是各種類似的 Provider 都是 ProviderBase 的子類撮珠,所以我們先解析 ProviderBase沮脖。

在 RiverPod 內(nèi)部,每個(gè) ProviderBase 的子類都會(huì)有其對(duì)應(yīng)的 ProviderElementBase 子類實(shí)現(xiàn) 芯急,例如前面代碼使用的 StateProviderProviderBase 的之類勺届,同樣它也有對(duì)應(yīng)的 StateProviderElementProviderElementBase 的子類;

所以 RiverPod 里基本是每一個(gè) “Provider” 都會(huì)有一個(gè)自己的 “Element” 娶耍。

??這里的 “Element” 不是 Flutter 概念里三棵樹(shù)的 Element免姿,它是 RiverPod 里 Ref 對(duì)象的子類Ref 主要提供 RiverPod 內(nèi)的 “Provider” 之間交互的接口榕酒,并且提供一些抽象的生命周期方法胚膊,所以它是 RiverPod 里的獨(dú)有的 “Element” 單位。

那 “Provider” 和 “Element” 的作用是什么想鹰?

首先紊婉,在上面例子里我們構(gòu)建 StateProvider 時(shí)傳入的 (ref) => 0 ,其實(shí)就是 Create<State, StateProviderRef<State>> 函數(shù)杖挣,我們就從這個(gè) Create 函數(shù)作為入口來(lái)探索肩榕。

Create<T, R extends Ref> = T Function(R ref)

RiverPod 里構(gòu)建 “Provider” 時(shí)都會(huì)傳入一個(gè) Create 函數(shù),而這個(gè)函數(shù)里一遍我們會(huì)寫一些需要的業(yè)務(wù)邏輯,比如 counterProvider 里的 ()=> 0 就是初始化時(shí)返回一個(gè) int 為 0 的值株汉,更重要的是決定了 State 的類型筐乳。

如果在上面代碼的基礎(chǔ)上增加了 <int> 就更明顯,事實(shí)上前面我們一直在說(shuō)的 State 就是一個(gè)泛型乔妈,而我們定義 “Provider” 就需要定義這個(gè)泛型 State 的類型蝙云,比如這里的 int

回歸到普通 Provider 的調(diào)用路召,我們傳入的 Create 函數(shù)勃刨,其實(shí)就是在 ProviderElementBase 里被調(diào)用執(zhí)行

如上圖所示股淡,簡(jiǎn)單來(lái)說(shuō)當(dāng) ProviderElementBase 執(zhí)行 “setState” 時(shí)身隐,就會(huì)調(diào)用 Create 函數(shù),從而執(zhí)行獲取到我們定義的泛型 State唯灵,得到 Result 然后通知并更新 UI贾铝。

?? 這里的 “setState” 也不是 Flutter Framework 里的 setState ,而是 RiverPod 內(nèi)自己首先的一個(gè) “setState” 函數(shù)埠帕,和 Flutter 框架里的 State 無(wú)關(guān)垢揩。

所以每個(gè) “Provider” 都會(huì)有自己的 “Element” ,而構(gòu)建 “Provider” 時(shí)是傳入的 Create 函數(shù)會(huì)在 “Element” 內(nèi)通過(guò) setState 調(diào)用執(zhí)行敛瓷。

“Element” 里的 setState 主要是通過(guò)新的 newState 去得到一個(gè) RiverPod 里的 Result 對(duì)象叁巨,然后通過(guò) _notifyListeners 去把得到 Result 更新到 watch 的地方。

Result 的作用主要是通過(guò) Result.data 呐籽、Result.error锋勺、 maprequireState 等去提供執(zhí)行結(jié)果,一般情況下?tīng)顟B(tài)都是通過(guò) requireState 獲取绝淡,具體在 RiverPod 體現(xiàn)為:

我們調(diào)用 read() 時(shí)宙刘,其實(shí)最后都調(diào)用到 element.readSelf(); ,也就是返回 requireState (其實(shí)一般也就是我們的泛型 State) 牢酵。

是不是有點(diǎn)亂悬包?

簡(jiǎn)單點(diǎn)理解就是:構(gòu)建出 “Provider” 之后, “Element” 里會(huì)執(zhí)行setState(_provider.create(this)); 調(diào)用我們傳入的 Create 函數(shù)馍乙,并把 “Element” 自己作為 ref 傳入進(jìn)入布近,所以我們使用的 ref 其實(shí)就是 ProviderElementBase

所以 RiverPod 里的起名是有原因的丝格,這里的 “Provider” 和 “Element” 的關(guān)系就很有 Flutter 里 WidgetElement 的即視感撑瞧。

分步驟來(lái)說(shuō)就是:

  • 構(gòu)建 Provider 時(shí)我們傳入了一個(gè) Create 函數(shù);
  • Create 函數(shù)會(huì)被 ProviderElementBase 內(nèi)部的 setState 所調(diào)用显蝌,得到一個(gè) Reuslt预伺;
  • Reuslt 內(nèi)的 requireState 就可以讓我們?cè)谑褂?read() 的時(shí)候,獲取到我們定義的 泛型 State 的值。

WidgetRef

前面介紹了那么多酬诀,但還是沒(méi)有說(shuō) StateProvider 怎么和 ProviderScope 關(guān)聯(lián)到一起脏嚷,也就是 “Provider” 怎么和 ProviderContainer 關(guān)聯(lián)到一起,憑什么 ref.read 就可以讀到 State 瞒御?

那么前面代碼里父叙,我們用到的 ConsumerWidgetConsumer 都是同個(gè)東西,而這個(gè) ref 就是前面我們一直說(shuō)的 “Element” 肴裙,或者說(shuō)是 ProviderElementBase 趾唱。

在源碼里可以看到, ConsumerWidget 的邏輯主要在 ConsumerStatefulElement蜻懦, 而ConsumerStatefulElement 繼承了 StatefulElement 甜癞,并實(shí)現(xiàn)了 WidgetRef 接口。

如上代碼就可以看到前面很多熟悉的身影了: ProviderScope 阻肩、ProviderContainer 带欢、 WidgetRef 运授。

首先我們看 ProviderScope.containerOf(this) 烤惊,終于看到我們熟悉的 BuildContext 有沒(méi)有,這個(gè)方法其實(shí)就是以前我們常用的 of(context) 吁朦,但是它被放到了 ConsumerStatefulElement 使用柒室,用于獲取 ProviderScope 往下共享的 ProviderContainer

所以我們看到了逗宜,ConsumerWidget 里的 ConsumerStatefulElement 獲取到了 ProviderContainer 雄右,所以 ConsumerStatefulElement 可以調(diào)用到 ProviderContainer 的 read/watch

然后回過(guò)頭來(lái)看纺讲,ConsumerStatefulElement 實(shí)現(xiàn)了 WidgetRef 接口擂仍,所以 我們使用的 WidgetRef 就是 ConsumerStatefulElement 本身

也就是 ref.read 就是執(zhí)行 ConsumerStatefulElementread , 從而執(zhí)行到 ProviderContainerread熬甚。

所以我們可以總結(jié): BuildContextElement 逢渔, 然后 Element 又實(shí)現(xiàn)了 WidgetRef ,所以此時(shí)的 WidgetRef 就是 BuildContext 的替代乡括。

這里不要把 Flutter 的 Element 和 RiverPod 里的 “ProviderElementBase” 搞混了肃廓。

所以 WidgetRef 這個(gè)接口成為了 Element 的抽象,替代了 BuildContext 诲泌,所以這就是 Riverpod 的“魔法”之一 盲赊。

read

所以前面我們已經(jīng)理清了 ProviderScopeProvider 敷扫、 ProviderElementBase哀蘑、 ProviderContainerConsumerWidgetConsumerStatefulElement) 和 WidgetRef 等的關(guān)系和功能,那最后我們就可以開(kāi)始理清楚 read 的整個(gè)工作鏈條绘迁。

我們理清和知道了 的概念與作用之后惨险,結(jié)合 ref.read 來(lái)做一個(gè)流程分析,那整體就是:

  • ConsumerWidget 會(huì)通過(guò)內(nèi)部的 ConsumerStatefulElement 獲取到頂層 ProviderScope 內(nèi)共享的 ProviderContainer 脊髓;
  • 當(dāng)我們通過(guò) ref 調(diào)用 read/watch 時(shí)辫愉,其實(shí)就是通過(guò) ConsumerStatefulElement 去調(diào)用 ProviderContainer 內(nèi)的 read 函數(shù);

那最后就是 ProviderContainer 內(nèi)的 read 函數(shù)如何讀取到 State将硝?

這就要結(jié)合前面我們同樣介紹過(guò)的 ProviderElementBase 恭朗, 事實(shí)上 ProviderContainer 在執(zhí)行 read 函數(shù)時(shí)會(huì)調(diào)用 readProviderElement

readProviderElement 顧名思義就是通過(guò) Provider 去獲取到對(duì)應(yīng)的 Element依疼,例如 :

ref.read(counterProvider),

一般情況下 read/watch 簡(jiǎn)單來(lái)說(shuō)就是從 ProviderContainer 里用 proivder 做 key 獲取得到 ProviderElementBase 這個(gè) “Element”痰腮,這個(gè)過(guò)程又有一個(gè)新的對(duì)象需要簡(jiǎn)單介紹下,就是:_StateReader律罢。

readProviderElement 其中一個(gè)關(guān)鍵就是獲取 _StateReader 膀值,在 ProviderContainer 里有一個(gè) _stateReaders 的內(nèi)部變量,它就是用于緩存 _StateReader 的 Map 误辑。

所以在 ProviderContainer 內(nèi)部:

  • 1沧踏、首先會(huì)根據(jù) read 時(shí)傳入的 provider 構(gòu)建得到一個(gè) _StateReader
  • 2巾钉、以 provider 為 key 翘狱, _StateReader 為 value 存入 _stateReaders 這個(gè) Map,并返回 _StateReader 砰苍;
  • 3潦匈、通過(guò) _StateReadergetElement() 獲取或者創(chuàng)建到 ProviderElementBase

這里的以 ProviderBase 為 Key 赚导, _StateReader 為 value 存入 _stateReaders 茬缩,其實(shí)就是把 “provider” 存入到了 ProviderContainer,也就是和 ProviderScope 關(guān)聯(lián)起來(lái)吼旧,也就是自此 “provider” 和 ProviderScope 就綁定到一起凰锡。

沒(méi)用使用到明面上的 BuildContext 和多余的嵌套,就讓 ProviderProviderScope 關(guān)聯(lián)起來(lái)黍少。 另外這里可以看到寡夹,ref.read 時(shí),如何通過(guò) provider 構(gòu)建或者獲取到 ProviderElementBase厂置。

得到 ProviderElementBase 還記得前面我們介紹 “Provider” 和 "Element" 的部分嗎菩掏?ProviderElementBase 會(huì)調(diào)用 setState 來(lái)執(zhí)行我們傳入的 Create 函數(shù),得到 Result 返回 State 昵济。

可以看到智绸,這里獲取的 ProviderElementBase 之后 return element.readSelf() 野揪,其實(shí)就是返回了 requireState

自從整個(gè) RiverPod 里最簡(jiǎn)單的 ref.read 流程就全線貫通了

  • ProviderScope 往下共享 ProviderContainer 瞧栗;

  • ConsumerWidget 內(nèi)部的 ConsumerStatefulElement 通過(guò) BuildContext 讀取到 ProviderContainer斯稳, 并且實(shí)現(xiàn) WidgetRef 接口;

  • 通過(guò) WidgetRef 接口的 read(provider) 調(diào)用到 ProviderContainer 里的 read迹恐;

  • ProviderContainer 通過(guò) read 方法的 provider 創(chuàng)建或者獲取得到 ProviderElementBase

  • ProviderElementBase 會(huì)執(zhí)行 provider 里的 Create 函數(shù)挣惰,來(lái)得到 Result 返回 State

其他的watch殴边,refresh 流程大同小異憎茂,就是一些具體內(nèi)部實(shí)現(xiàn)邏輯更復(fù)雜而已,比如刷新時(shí):

通過(guò) ref.refresh 方法锤岸, 其實(shí)觸發(fā)的就是 ProviderContainerrefresh 竖幔,然后最終還是會(huì)通過(guò) _buildState 去觸發(fā) setState(_provider.create(this)) 的執(zhí)行。

而從這個(gè)流程分析是偷,也看到了 RiverPod 如何不暴露使用 BuildContext 實(shí)現(xiàn)全線關(guān)聯(lián)的邏輯拳氢。

額外分析

前面基本介紹完整個(gè)調(diào)用流程,這里在額外介紹一些常見(jiàn)的調(diào)用時(shí)如何實(shí)現(xiàn)蛋铆,比如在 Riverpod 里面會(huì)看到很多 “Element” 馋评,比如 ProviderElementStreamProviderElement 戒职、 FutureProviderElement 等這些 ProviderElementBase 的子類栗恩。

我們結(jié)果過(guò)它們并不是 Flutter 里的 Element 禽炬,而是 Riverpod 里的的 State 單位步淹,用于處理 Provider 的狀態(tài)轻姿,比如 FutureProviderElement 就是在 ProviderElementBase 的基礎(chǔ)上提供一個(gè) AsyncValue<State>,主要在 FutureProvider 里使用捧韵。

AsyncValue

在 RiverPod 里正常情況下的 create 方法定義是如下所示:

而在 FutureProvider 下是多了一個(gè) _listenFuture,這個(gè) Function 執(zhí)行后的 value 就會(huì)是 AsyncValue<State> 的 State 類型汉操。

_listenFuture 的執(zhí)行上看再来, 內(nèi)部會(huì)對(duì)這個(gè) future() 執(zhí)行,會(huì)先進(jìn)入 AsyncValue<State>.loading() 之后磷瘤,根據(jù) Future 的結(jié)果返回決定返回AsyncValue<State>.data 或者 AsyncValue<State>.error 芒篷。

所以比如在 read / watch 時(shí),返回的泛型 requireState 其實(shí)變成了 AsyncValue<State>采缚。

而針對(duì) AsyncValue 官方做了一些 extension 针炉,在 AsyncValueX 上,其中出了獲取 AsyncDatadata \ asData 和 T value 之外扳抽,最主要提供了起那么所說(shuō)的不同狀態(tài)的構(gòu)建方法篡帕,比如 when 方法:

autoDispose & family

在 Riverpod 里應(yīng)該還很常見(jiàn)一個(gè)叫 autoDisposefamily 的靜態(tài)變量殖侵,幾乎每個(gè) Provider 都有,又是用來(lái)干什么的呢镰烧?

舉個(gè)例子拢军,前面代碼里我們有個(gè) FutureProvider, 我們用到了里的 autoDispose

其實(shí) FutureProvider.autoDispose 主要就是 AutoDisposeFutureProvider 怔鳖,以此類推基本每個(gè) Provider 都有自己的 autoDispose 實(shí)現(xiàn)茉唉,family 也是同理

如果說(shuō)正常的 Provider 是繼承了 AlwaysAliveProviderBase结执,那 AutoDisposeProvider 就是繼承于 AutoDisposeProviderBase :

從名字可以看出來(lái):

  • AlwaysAliveProviderBase 是一只活躍的赌渣;
  • AutoDisposeProviderBase 自然就是不 listened 的時(shí)候就銷毀;

也就是內(nèi)部 _listeners 昌犹、_subscribers坚芜、_dependents 都是空的時(shí)候,當(dāng)然它還有另外一個(gè) maintainState 的控制狀態(tài)斜姥,默認(rèn)它就是 false 的時(shí)候鸿竖,就可以執(zhí)行銷毀。

簡(jiǎn)單理解就是用“完即焚燒” 铸敏。

比如前面我們介紹調(diào)用 read 的時(shí)候缚忧,都會(huì)調(diào)用 mayNeedDispose 去嘗試銷毀:

銷毀也就是調(diào)用 element.dispose() 和從 _stateReaders 這個(gè) map 里移除等等。

同樣的 family 對(duì)應(yīng)是 ProviderFamily杈笔,它的作用是:使用額外的參數(shù)構(gòu)建 provider 闪水,也即是增加一個(gè)參數(shù)

例如默認(rèn)是把 :

final tagThemeProvider  = Provider<TagTheme> 

可以變成

final tagThemeProvider2  = Provider.family<TagTheme, Color>

然后你就可以使用額外的參數(shù)蒙具,在 read/watch 的時(shí)候 :

final questionsCountProvider = Provider.autoDispose((ref) {
  return ref
      .watch(tagThemeProvider2(Colors.red));
});

之所以可以實(shí)現(xiàn)這個(gè)功能球榆,就要看它的實(shí)現(xiàn) ProviderFamily ,對(duì)比一般 Provider 默認(rèn)的 create 禁筏,ProviderFamily 的是:

可以看到 create 的是新的一個(gè) Provider持钉,也就是 family 下其實(shí)是 Provider 嵌套 Provider

所以從上面的例子出發(fā)篱昔,以前我們是通過(guò) ref.watch(tagThemeProvider); 就可以了每强,因?yàn)槲覀兊?tagThemeProvider 的直接就是 ProviderBase

但是如果使用 ref.watch(tagThemeProvider2); 就會(huì)看到錯(cuò)誤提示

The argument type 'ProviderFamily<TagTheme, Color>' can't be assigned to the parameter type 'ProviderListenable<dynamic>'. 

是的州刽,因?yàn)檫@里是 Provider 嵌套 Provider 空执,我們先得到是的 ProviderFamily<TagTheme, Color> ,所以我們需要改為 ref.watch(tagThemeProvider2(Colors.red)); 穗椅。

通過(guò) tagThemeProvider2(Colors.red) 執(zhí)行一次變?yōu)槲覀冃枰?ProviderBase 辨绊。

tagThemeProvider2 這個(gè) ProviderFamily 為什么是這樣執(zhí)行? ProviderFamily 明明沒(méi)有這樣的構(gòu)造函數(shù)房待。

這就涉及到 Dart 語(yǔ)言的特性邢羔,如果有興趣可以看 : juejin.cn/post/696836…

首先這里拿到的是一個(gè) ProviderFamily<TagTheme, Color> 驼抹,在 Dart 中所有函數(shù)類型都是 Function 的子類型,所以函數(shù)都固有地具有 call 方法拜鹤。

我們執(zhí)行 tagThemeProvider2(Colors.red) 其實(shí)就是執(zhí)行了 ProviderFamilycall 方法框冀,從而執(zhí)行了 create 方法,得到 FamilyProvider<State> 敏簿,FamilyProvider 也就是 ProviderBase 的子類 明也。

??注意這里有點(diǎn)容易看錯(cuò)的地方,一個(gè)是 ProviderFamily 惯裕, 一個(gè)是 FamilyProvider温数, 我們從 ProviderFamily 里面得到了 FamilyProvider, 作為 ProviderBaseref.watch 蜻势。

最后

很久沒(méi)有寫這么長(zhǎng)的源碼分析了撑刺,不知不覺(jué)就寫到了半夜凌晨,其實(shí)相對(duì)來(lái)說(shuō)握玛,整個(gè) Riverpod 更加復(fù)雜够傍,所以閱讀起來(lái)也更加麻煩,但是使用起來(lái)反而會(huì)相對(duì)更便捷挠铲,特別是沒(méi)有了 BuildContext 的限制冕屯,但是同時(shí)也是帶來(lái)了 ConsumerWidget 的依賴,所有利弊只能看你自己的需求拂苹,但是整體 Riverpod 肯定是一個(gè)優(yōu)秀的框架安聘,值得一試。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瓢棒,一起剝皮案震驚了整個(gè)濱河市浴韭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌音羞,老刑警劉巖囱桨,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嗅绰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)搀继,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門窘面,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人叽躯,你說(shuō)我怎么就攤上這事财边。” “怎么了点骑?”我有些...
    開(kāi)封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵酣难,是天一觀的道長(zhǎng)谍夭。 經(jīng)常有香客問(wèn)我,道長(zhǎng)憨募,這世上最難降的妖魔是什么紧索? 我笑而不...
    開(kāi)封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮菜谣,結(jié)果婚禮上珠漂,老公的妹妹穿的比我還像新娘。我一直安慰自己尾膊,他們只是感情好媳危,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著冈敛,像睡著了一般待笑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抓谴,一...
    開(kāi)封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天暮蹂,我揣著相機(jī)與錄音,去河邊找鬼齐邦。 笑死椎侠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的措拇。 我是一名探鬼主播我纪,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼丐吓!你這毒婦竟也來(lái)了浅悉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤券犁,失蹤者是張志新(化名)和其女友劉穎术健,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體粘衬,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荞估,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稚新。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勘伺。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖褂删,靈堂內(nèi)的尸體忽然破棺而出飞醉,到底是詐尸還是另有隱情,我是刑警寧澤屯阀,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布缅帘,位于F島的核電站轴术,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏钦无。R本人自食惡果不足惜逗栽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铃诬。 院中可真熱鬧祭陷,春花似錦、人聲如沸趣席。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宣肚。三九已至想罕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霉涨,已是汗流浹背按价。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笙瑟,地道東北人楼镐。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像往枷,于是被迫代替她去往敵國(guó)和親框产。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容