0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

State改變時(shí)組件如何刷新

谷歌開發(fā)者 ? 來源:BennuCTech ? 作者:BennuC ? 2022-07-22 09:42 ? 次閱讀

生命周期

Flutter 的生命周期其實(shí)有兩種: StatefulWidget 和 StatelessWidget。 這兩個(gè)是 Flutter 的兩個(gè)基本組件,名稱已經(jīng)很好表明了這兩個(gè)組件的功能:有狀態(tài)和無狀態(tài)。

StatelessWidget

StatelessWidget 是無狀態(tài)組件,它的生命周期非常簡(jiǎn)單,只有一個(gè) build,如下:
class WidgetA extends StatelessWidget {  @override  Widget build(BuildContext context) {    return ...;  }}
對(duì)于 StatelessWidget 來說只渲染一次,之后它就不再有任何改變。

由于無狀態(tài)組件在執(zhí)行過程中只有一個(gè) build 階段,在執(zhí)行期間只會(huì)執(zhí)行一個(gè) build 函數(shù),沒有其他生命周期函數(shù),因此在執(zhí)行速度和效率方面比有狀態(tài)組件更好。所以在設(shè)計(jì)組件時(shí),要考慮業(yè)務(wù)情況,盡量使用無狀態(tài)組件。

StatefulWidgetStatelessWidget 是有狀態(tài)組件,我們討論的生命周期也基本指它的周期,如圖:8566ce84-095f-11ed-ba43-dac502259ad0.jpg

包含以下幾個(gè)階段:

  • createState該函數(shù)為 StatefulWidget 中創(chuàng)建 State 的方法,當(dāng) StatefulWidget 被調(diào)用時(shí)會(huì)立即執(zhí)行 createState。
  • initState
  • 該函數(shù)為 State 初始化調(diào)用,因此可以在此期間執(zhí)行 State 各變量的初始賦值,同時(shí)也可以在此期間與服務(wù)端交互,獲取服務(wù)端數(shù)據(jù)后調(diào)用 setState 來設(shè)置 State。
  • didChangeDependencies該函數(shù)是在該組件依賴的 State 發(fā)生變化時(shí),這里說的 State 為全局 State,例如語言或者主題等,類似于前端 Redux 存儲(chǔ)的 State。
  • build主要是返回需要渲染的 Widget,由于 build 會(huì)被調(diào)用多次,因此在該函數(shù)中只能做返回 Widget 相關(guān)邏輯,避免因?yàn)閳?zhí)行多次導(dǎo)致狀態(tài)異常,注意這里的性能問題。
  • reassemble主要是提供開發(fā)階段使用,在 debug 模式下,每次熱重載都會(huì)調(diào)用該函數(shù),因此在 debug 階段可以在此期間增加一些 debug 代碼,來檢查代碼問題。
  • didUpdateWidget該函數(shù)主要是在組件重新構(gòu)建,比如說熱重載,父組件發(fā)生 build 的情況下,子組件該方法才會(huì)被調(diào)用,其次該方法調(diào)用之后一定會(huì)再調(diào)用本組件中的 build 方法。
  • deactivate在組件被移除節(jié)點(diǎn)后會(huì)被調(diào)用,如果該組件被移除節(jié)點(diǎn),然后未被插入到其他節(jié)點(diǎn)時(shí),則會(huì)繼續(xù)調(diào)用 dispose 永久移除。
  • dispose永久移除組件,并釋放組件資源。
在 StatelessWidget 中,只要我們調(diào)用 setState,就會(huì)執(zhí)行重繪,也就是說重新執(zhí)行 build 函數(shù),這樣就可以改變 UI。

State 改變時(shí)組件如何刷新

先來看看下方的代碼:


class MyHomePage extends StatefulWidget {
  @override  _MyHomePageState createState() => _MyHomePageState();}
class _MyHomePageState extends State<MyHomePage> {  int _counter = 0;
  void _incrementCounter() {    setState(() {      _counter++;    });  }
  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            WidgetA(_counter),            WidgetB(),            WidgetC(_incrementCounter)          ],        ),      ),    );  }}
class WidgetA extends StatelessWidget {  final int counter;
  WidgetA(this.counter);
  @override  Widget build(BuildContext context) {    return Center(      child: Text(counter.toString()),    );  }}
class WidgetB extends StatelessWidget {  @override  Widget build(BuildContext context) {    return Text('I am a widget that will not be rebuilt.');  }}
class WidgetC extends StatelessWidget {  final void Function() incrementCounter;
  WidgetC(this.incrementCounter);
  @override  Widget build(BuildContext context) {    return RaisedButton(      onPressed: () {        incrementCounter();      },      child: Icon(Icons.add),    );  }}

我們有三個(gè) Widget,一個(gè)負(fù)責(zé)顯示 count,一個(gè)按鈕改變 count,一個(gè)則是靜態(tài)顯示文字,通過這三個(gè) Widget 來對(duì)比比較頁面的刷新邏輯。

上面代碼中,三個(gè) Widget 是在 _MyHomePageState 的 build 中創(chuàng)建的,執(zhí)行后點(diǎn)擊按鈕可以發(fā)現(xiàn)三個(gè) Widget 都刷新了。

在 Flutter Performance 面板上選中 Track Widget Rebuilds 即可看到

8575d8d4-095f-11ed-ba43-dac502259ad0.jpg

雖然三個(gè) Widget 都是無狀態(tài)的 StatelessWidget,但是因?yàn)?_MyHomePageState 的 State 改變時(shí)會(huì)重新執(zhí)行 build 函數(shù),所以三個(gè) Widget 會(huì)重新創(chuàng)建,這也是為什么 WidgetA 雖然是無狀態(tài)的 StatelessWidget 卻依然可以動(dòng)態(tài)改變的原因。

所以: 無狀態(tài)的 StatelessWidget 并不是不能動(dòng)態(tài)改變,只是在其內(nèi)部無法通過 State 改變,但是其父 Widget 的 State 改變時(shí)可以改變其構(gòu)造參數(shù)使其改變。實(shí)際上確實(shí)不能改變,因?yàn)槭且粋€(gè)新的實(shí)例。

下面我們將三個(gè)組件提前創(chuàng)建,可以在 _MyHomePageState 的構(gòu)造函數(shù)中創(chuàng)建,修改后代碼如下:


class_MyHomePageStateextendsState<MyHomePage>{  int _counter = 0;  List children;
  _MyHomePageState(){    children = [      WidgetA(_counter),      WidgetB(),      WidgetC(_incrementCounter)    ];  }
  void _incrementCounter() {    setState(() {      _counter++;    });  }
  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: children,        ),      ),    );  }}

再次執(zhí)行,發(fā)現(xiàn)點(diǎn)擊沒有任何效果,F(xiàn)lutter Performance 上可以看到?jīng)]有 Widget 刷新 (這里指三個(gè) Widget,當(dāng)然 Scaffold 還是刷新了)。

這是因?yàn)榻M件都提前創(chuàng)建了,所以執(zhí)行 build 時(shí)沒有重新創(chuàng)建三個(gè) Widget,所以 WidgetA 顯示的內(nèi)容并沒有改變,因?yàn)樗?counter 沒有重新傳入。

所以,不需要?jiǎng)討B(tài)改變的組件可以提前創(chuàng)建,build 時(shí)直接使用即可,而需要?jiǎng)討B(tài)改變的組件實(shí)時(shí)創(chuàng)建。

這樣就可以實(shí)現(xiàn)局部刷新了么?我們繼續(xù)改動(dòng)代碼如下:


class_MyHomePageStateextendsState{  int _counter = 0;  Widget b = WidgetB();  Widget c ;
  _MyHomePageState(){    c = WidgetC(_incrementCounter);  }
  void _incrementCounter() {    setState(() {      _counter++;    });  }
  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            WidgetA(_counter),            b,            c          ],        ),      ),    );  }}
我們只將 WidgetB 和 WidgetC 重新創(chuàng)建,而 WidgetA 則在 build 中創(chuàng)建。執(zhí)行后,點(diǎn)擊按鈕 WidgetA 的內(nèi)容改變了,查看 Flutter Performance 可以看到只有 WidgetA 刷新了,WidgetB 和 WidgetC 沒有刷新。

8581079a-095f-11ed-ba43-dac502259ad0.jpg

所以: 通過提前創(chuàng)建靜態(tài)組件 build 時(shí)直接使用,而 build 時(shí)直接創(chuàng)建動(dòng)態(tài) Widget 這種方式可以實(shí)現(xiàn)局部刷新。

注意:只要 setState,_MyHomePageState 就會(huì)刷新,所以 WidgetA 就會(huì)跟著刷新,即使 count 沒有改變。比如上面代碼中將 setState 中的 _count++ 代碼注釋掉,再點(diǎn)擊按鈕雖然內(nèi)容沒有改變,但是 WidgetA 依然刷新。

這種情況可以通過 InheritedWidget 來進(jìn)行優(yōu)化。

InheritedWidget

InheritedWidget 的作用什么?網(wǎng)上有人說是數(shù)據(jù)共享,有人說是用于局部刷新。我們看官方的描述:

Baseclassforwidgetsthatefficientlypropagateinformationdownthetree.

可以看到它的作用是 Widget 樹從上到下有效的傳遞消息,所以很多人理解為數(shù)據(jù)共享,但是注意這個(gè) "有效的",這個(gè)才是它的關(guān)鍵,而這個(gè)有效的其實(shí)就是解決上面提到的問題。

那么它怎么使用?

先創(chuàng)建一個(gè)繼承至 InheritedWidget 的類:


class MyInheriteWidget extends InheritedWidget{  final int count;  MyInheriteWidget({@required this.count, Widget child}) : super(child: child);
  static MyInheriteWidget of(BuildContext context){    return context.dependOnInheritedWidgetOfExactType();  }
  @override  bool updateShouldNotify(MyInheriteWidget oldWidget) {    return oldWidget.count != count;  }}

這里將 count 傳入。重點(diǎn)注意要實(shí)現(xiàn) updateShouldNotify 函數(shù),通過名字可以知道這個(gè)函數(shù)決定 InheritedWidget 的 Child Widget 是否需要刷新,這里我們判斷如果與之前改變了才刷新。這樣就解決了上面提到的問題。

然后還要實(shí)現(xiàn)一個(gè) static 的 of 方法,用于 Child Widget 中獲取這個(gè) InheritedWidget,這樣就可以訪問它的 count 屬性了,這就是消息傳遞,即所謂的數(shù)據(jù)共享 (因?yàn)?InheritedWidget 的 child 可以是一個(gè) layout,里面有多個(gè) widget,這些 widget 都可以使用這個(gè) InheritedWidget 中的數(shù)據(jù))。

然后我們改造一下 WidgetA:


classWidgetAextendsStatelessWidget{
  @override  Widget build(BuildContext context) {    final MyInheriteWidget myInheriteWidget = MyInheriteWidget.of(context);    return Center(      child: Text(myInheriteWidget.count.toString()),    );  }}

這次不用在構(gòu)造函數(shù)中傳遞 count 了,直接通過 of 獲取 MyInheriteWidget,使用它的 count 即可。

最后修改 _MyHomePageState:


class _MyHomePageState extends State {  int _counter = 0;  Widget a = WidgetA();  Widget b = WidgetB();  Widget c ;
  _MyHomePageState(){    c = WidgetC(_incrementCounter);  }
  void _incrementCounter() {    setState(() {      _counter++;    });  }
  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            MyInheriteWidget(              count: _counter,              child: a,            ),            b,            c          ],        ),      ),    );  }}

注意,這里用 MyInheriteWidget 包裝一下 WidgetA,而且 WidgetA 必須提前創(chuàng)建,如果在 build 中創(chuàng)建則每次 MyInheriteWidget 刷新都會(huì)跟著刷新,這樣 updateShouldNotify 函數(shù)的效果就無法達(dá)到。

執(zhí)行,點(diǎn)擊按鈕,可以發(fā)現(xiàn)只有 WidgetA 刷新了 (當(dāng)然 MyInheriteWidget 也刷新了)。如果注釋掉 setState 中的 _count++ 代碼,再執(zhí)行并點(diǎn)擊發(fā)現(xiàn)雖然 MyInheriteWidget 刷新了,但是 WidgetA 并不刷新,因?yàn)?MyInheriteWidget 的 count 并未改變。

下面我們改動(dòng)一下代碼,將 WidgetB 和 C 都放入 MyInheriteWidget 會(huì)怎樣?


@override  Widget build(BuildContext context) {    return Scaffold(      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            MyInheriteWidget(              count: _counter,              child: Column(                children: [                  a,                  b,                  c                ],              ),            ),          ],        ),      ),    );  }}

MyInheriteWidget 的 child 是一個(gè) Column,將 a、b、c 都放在這下面。執(zhí)行會(huì)發(fā)現(xiàn)依然是 WidgetA 刷新,B 和 C 都不刷新。這是因?yàn)樵?B 和 C 中沒有執(zhí)行 MyInheriteWidget 的 of 函數(shù),就沒有執(zhí)行 dependOnInheritedWidgetOfExactType,這樣其實(shí)就沒構(gòu)成依賴,MyInheriteWidget 就不會(huì)通知它們。

如果我們修改 WidgetC,在 build 函數(shù)中添加一行 MyInheriteWidget.of(context); 那么雖然沒有任何使用,依然會(huì)跟著刷新,因?yàn)榻⒘艘蕾囮P(guān)系就會(huì)被通知。

InheritedWidget 會(huì)解決多余的刷新問題,比如在一個(gè)頁面中有多個(gè)屬性,同樣有多個(gè) Widget 來使用這些屬性,但是并不是每個(gè) Widget 都使用所有屬性。如果用最普通的實(shí)現(xiàn)方式,那么每次 setState (無論改變哪個(gè)屬性) 都需要刷新這些 Widget。但是如果我們用多個(gè) InheritedWidget 來為這些 Widget 分類,使用相同屬性的用同一個(gè) InheritedWidget 來包裝,并實(shí)現(xiàn) updateShouldNotify,這樣當(dāng)改變其中一個(gè)屬性時(shí),只有該屬性相關(guān)的 InheritedWidget 才會(huì)刷新它的 child,這樣就提高了性能。

InheritedModel

InheritedModel 是繼承至 InheritedWidget 的,擴(kuò)充了它的功能,所以它的功能更加強(qiáng)大。具體提現(xiàn)在哪里呢?

通過上面我們知道,InheritedWidget 可以通過判斷它的 data 是否變化來決定是否刷新 child,但是實(shí)際情況下這個(gè) data 可以是多個(gè)變量或者一個(gè)復(fù)雜的對(duì)象,而 child 也不是單一 widget,而是一系列 widget 組合。比如展示一本書,數(shù)據(jù)可能有書名、序列號(hào)、日期等等,但是每個(gè)數(shù)據(jù)可能單獨(dú)變化,如果用 InheritedWidget,每種數(shù)據(jù)就需要一個(gè) InheritedWidget 類,然后將使用該數(shù)據(jù)的 widget 包裝,這樣才能包裝改變某個(gè)數(shù)據(jù)時(shí)其他 widget 不刷新。

但是這樣的問題就是 widget 層級(jí)更加復(fù)雜混亂,InheritedModel 就可以解決這個(gè)問題。InheritedModel 最大的功能就是根據(jù)不同數(shù)據(jù)的變化刷新不同的 widget。下面來看看如何實(shí)現(xiàn)。

首先創(chuàng)建一個(gè) InheritedModel:


class MyInheriteModel extends InheritedModel<String>{  final int count1;  final int count2;  MyInheriteModel({@required this.count1, @required this.count2, Widget child}) : super(child: child);
  static MyInheriteModel of(BuildContext context, String aspect){    return InheritedModel.inheritFrom(context, aspect: aspect);  }
  @override  bool updateShouldNotify(MyInheriteModel oldWidget) {    return count1 != oldWidget.count1 || count2 != oldWidget.count2;  }
  @override  bool updateShouldNotifyDependent(MyInheriteModel oldWidget, Set dependencies) {    return (count1 != oldWidget.count1 && dependencies.contains("count1")) ||        (count2 != oldWidget.count2 && dependencies.contains("count2"));  }}
這里我們傳入兩個(gè) count,除了實(shí)現(xiàn) updateShouldNotify 方法,還需要實(shí)現(xiàn) updateShouldNotifyDependent 方法。這個(gè)函數(shù)就是關(guān)鍵,可以看到我們判斷某個(gè)數(shù)據(jù)是否變化后還判斷了 dependencies 中是否包含一個(gè)關(guān)鍵詞:

count1!=oldWidget.count1&&dependencies.contains("count1")
這個(gè)關(guān)鍵詞是什么?從哪里來?后面會(huì)提到,這里先有個(gè)印象。

然后同樣需要實(shí)現(xiàn)一個(gè) static 的 of 函數(shù)來獲取這個(gè) InheritedModel,不同的是這里獲取的代碼變化了:


InheritedModel.inheritFrom(context,aspect:aspect);
這里的 aspect 就是后面用到的關(guān)鍵字,而 inheritFrom 會(huì)將這個(gè)關(guān)鍵字放入 dependencies,以便 updateShouldNotifyDependent 來使用。后面會(huì)詳細(xì)解釋這個(gè) aspect 完整作用。

然后我們改造 WidgetA:


class WidgetA extends StatelessWidget {
  @override  Widget build(BuildContext context) {    final MyInheriteModel myInheriteModel = MyInheriteModel.of(context, "count1");    return Center(      child: Text(myInheriteModel.count1.toString()),    );  }}

可以看到,這里定義了 aspect。

然后因?yàn)橛袃蓚€(gè) count,所以我們?cè)傩略鰞蓚€(gè) Widget 來處理 count2:


class WidgetD extends StatelessWidget {
  @override  Widget build(BuildContext context) {    final MyInheriteModel myInheriteModel = MyInheriteModel.of(context, "count2");    return Center(      child: Text(myInheriteModel.count2.toString()),    );  }}
class WidgetE extends StatelessWidget {  final void Function() incrementCounter;
  WidgetE(this.incrementCounter);
  @override  Widget build(BuildContext context) {    return RaisedButton(      onPressed: () {        incrementCounter();      },      child: Icon(Icons.add),    );  }}

這里可以看到 WidgetD 的 aspect 與 WidgetA 是不同的。

最后修改 _MyHomePageState:


class _MyHomePageState extends State {  int _counter = 0;  int _counter2 = 0;  Widget a = Row(    children: [      WidgetA(),      WidgetD()    ],  );  Widget b = WidgetB();  Widget c ;  Widget e ;
  _MyHomePageState(){    c = WidgetC(_incrementCounter);    e = WidgetE(_incrementCounter2);  }
  void _incrementCounter() {    setState(() {      _counter++;    });  }
  void _incrementCounter2() {    setState(() {      _counter2++;    });  }
  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            MyInheriteModel(              count1: _counter,              count2: _counter2,              child: a,            ),            b,            c,            e          ],        ),      ),    );  }}

WidgetD 和 E 是處理 count2 的,A 和 C 則是處理 count。而 MyInheriteModel 的 child 不是單一 Widget,而是一個(gè) Row,包含 WidgetD 和 A。

執(zhí)行代碼,可以發(fā)現(xiàn)點(diǎn)擊 WidgetC 的時(shí)候,只有 WidgetA 刷新了 (當(dāng)然 MyInheriteModel 也刷新);而點(diǎn)擊 WidgetD 的時(shí)候,只有 WidgetE 刷新了。這樣我們就實(shí)現(xiàn)了 MyInheriteModel 中的局部刷新。 其實(shí)原理很簡(jiǎn)單,aspect 就相當(dāng)于一個(gè)標(biāo)記,當(dāng)我們通過 InheritedModel.inheritFrom(context, aspect: aspect); 獲取 MyInheriteModel 時(shí),實(shí)際上將本 Widget 依賴到 MyInheriteModel,并且將這個(gè) Widget 標(biāo)記。這時(shí)候如果 data 改變,遍歷它的所有依賴時(shí),會(huì)通過每個(gè)依賴的 Widget 獲取它對(duì)應(yīng)的標(biāo)記集 dependencies,然后觸發(fā) updateShouldNotifyDependent 判斷該 Widget 是否刷新。 所以在 InheritedModel (其實(shí)是 InheritedElement) 中存在一個(gè) map,記錄了每個(gè)依賴的 Widget 對(duì)應(yīng)的 dependencies,所以一個(gè) Widget 可以有多個(gè)標(biāo)記,因?yàn)?dependencies 是一個(gè) Set,這樣就可以響應(yīng)多個(gè)數(shù)據(jù)的變化 (比如多個(gè)數(shù)據(jù)組成一個(gè) String 作為文本顯示)。 上面其實(shí)可以用兩個(gè) InheritedWidget 也可以實(shí)現(xiàn),但是布局越復(fù)雜,就需要越多的 InheritedWidget,維護(hù)起來也費(fèi)時(shí)費(fèi)力。 所以可以看到 InheritedModel 使用更靈活,功能更強(qiáng)大,更適合復(fù)雜的數(shù)據(jù)和布局使用,并且通過細(xì)分細(xì)化每一個(gè)刷新區(qū)域,使得每次刷新都只更新最小區(qū)域,極大的提高了性能。

InheritedNotifier

InheritedNotifier 同樣繼承至 InheritedWidget,它是一個(gè)給 Listenable 的子類的專用工具,它的構(gòu)造函數(shù)中要傳入一個(gè) Listenable (這是一個(gè)接口,不再是之前的各種數(shù)據(jù) data),比如動(dòng)畫 (如 AnimationController),然后其依賴的組件則根據(jù) Listenable 進(jìn)行更新。 首先還是先創(chuàng)建一個(gè) InheritedNotifier:
class MyInheriteNotifier extends InheritedNotifier<AnimationController>{  MyInheriteNotifier({       Key key,       AnimationController notifier,       Widget child,     }) : super(key: key, notifier: notifier, child: child);
  static double of(BuildContext context){    return context.dependOnInheritedWidgetOfExactType().notifier.value;  }}

這里提供的 of 函數(shù)則直接返回 AnimationController 的 value 即可。

然后創(chuàng)建一個(gè) Widget:


classSpinnerextendsStatelessWidget{  @override  Widget build(BuildContext context) {    return Transform.rotate(      angle: MyInheriteNotifier.of(context) * 2 * pi,      child: Text("who!!"),    );  }}

內(nèi)容會(huì)根據(jù) AnimationController 進(jìn)行旋轉(zhuǎn)。

修改 WidgetA:


class WidgetA extends StatelessWidget {
  @override  Widget build(BuildContext context) {    return Center(      child: Text("WidgetA"),    );  }}
然后修改 _MyHomePageState:
class _MyHomePageState extends State with SingleTickerProviderStateMixin {  AnimationController _controller;
  @override  void initState() {    super.initState();    _controller = AnimationController(      vsync: this,      duration: Duration(seconds: 10),    )..repeat();  }
  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            WidgetA(),            MyInheriteNotifier(                notifier: _controller,                child: Spinner()            ),          ],        ),      ),    );  }}
運(yùn)行會(huì)看到 Text 在不停的旋轉(zhuǎn),當(dāng)然如果有其他 Widget 可以看到并不跟著刷新。

總之 InheritedNotifier 是一個(gè)更細(xì)化的工具,聚焦到一個(gè)具體場(chǎng)景中,使用起來也更方便。

Notifier

最后再簡(jiǎn)單介紹一下 Notifier,考慮一個(gè)需求: 頁面 A 是列表頁,而頁面 B 是詳情頁,兩個(gè)頁面都有點(diǎn)贊操作和顯示點(diǎn)贊數(shù)量,需要在一個(gè)頁面點(diǎn)贊后兩個(gè)頁面的數(shù)據(jù)同時(shí)刷新。這種情況下就可以使用 Flutter 提供另外一種方式 —— Notifier。

Notifier 其實(shí)就是訂閱模式的實(shí)現(xiàn),主要包含 ChangeNotifier 和 ValueNotifier,使用起來也非常簡(jiǎn)單。通過 addListener 和 removeListener 進(jìn)行訂閱和取消訂閱 (參數(shù)是無參無返回值的 function),當(dāng)數(shù)據(jù)改變時(shí)調(diào)用 notifyListeners(); 通知即可。

ValueNotifier 是更簡(jiǎn)單的 ChangeNotifier,只有一個(gè)數(shù)據(jù) value,可以直接進(jìn)行 set 和 get,set 時(shí)自動(dòng)執(zhí)行 notifyListeners(),所以適合單數(shù)據(jù)的簡(jiǎn)單場(chǎng)景。

當(dāng)時(shí)注意 Notifier 只是共享數(shù)據(jù)并通知變化,并不實(shí)現(xiàn)刷新,所以還要配合其他一并實(shí)現(xiàn)。比如上面的 InheritedNotifier (因?yàn)?Notifier 都繼承 Listenable 接口,所以兩個(gè)可以很簡(jiǎn)單的配合使用),或者第三方庫 Provider (web 開發(fā)的習(xí)慣) 等等。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4284

    瀏覽量

    62328
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4723

    瀏覽量

    68240
  • State
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    7653

原文標(biāo)題:Flutter 組件的生命周期、State 管理及局部重繪 | 開發(fā)者說·DTalk

文章出處:【微信號(hào):Google_Developers,微信公眾號(hào):谷歌開發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    隆基綠能刷新光伏晶硅組件效率世界紀(jì)錄

    近日,隆基綠能宣布了一項(xiàng)重大突破。據(jù)國際權(quán)威認(rèn)證機(jī)構(gòu)——德國弗勞霍夫太陽電池研究所最新發(fā)布的認(rèn)證報(bào)告顯示,隆基綠能自主研發(fā)的HPBC 2.0組件效率達(dá)到了驚人的25.4%,成功打破了晶硅組件效率的世界紀(jì)錄。
    的頭像 發(fā)表于 10-23 17:40 ?423次閱讀

    什么是存儲(chǔ)器的刷新

    存儲(chǔ)器的刷新是動(dòng)態(tài)隨機(jī)存取存儲(chǔ)器(DRAM)維護(hù)所存信息的一種重要機(jī)制。由于DRAM利用存儲(chǔ)元中的柵極電容來存儲(chǔ)電荷,而電容本身存在漏電流,導(dǎo)致電荷會(huì)逐漸流失,從而使得存儲(chǔ)的數(shù)據(jù)變得不可靠。為了保持
    的頭像 發(fā)表于 09-10 14:34 ?570次閱讀

    鴻蒙ArkTS容器組件:Refresh

    可以進(jìn)行頁面下拉操作并顯示刷新動(dòng)效的容器組件。
    的頭像 發(fā)表于 07-11 16:11 ?420次閱讀

    Jlink-V9固件刷新工具-J-link固件刷新

    Jlink-V9固件刷新工具 - J-link固件刷新針對(duì)J-link偶發(fā)損壞問題,進(jìn)行固件升級(jí)后解決問題。
    發(fā)表于 06-11 09:11 ?36次下載

    HarmonyOS實(shí)戰(zhàn)開發(fā)-合理選擇條件渲染和顯隱控制

    對(duì)于首頁初始時(shí),不需要顯示的組件,通過顯隱控制進(jìn)行隱藏。 @Entry @Component struct WorseUseVisibility { @State isVisible: boolean
    發(fā)表于 05-10 15:16

    HarmonyOS開發(fā)案例:【排行榜頁面】

    本課程使用聲明式語法和組件化基礎(chǔ)知識(shí),搭建一個(gè)可刷新的排行榜頁面。在排行榜頁面中,使用循環(huán)渲染控制語法來實(shí)現(xiàn)列表數(shù)據(jù)渲染,使用@Builder創(chuàng)建排行列表布局內(nèi)容,使用裝飾器@State、@Prop、@Link來管理
    的頭像 發(fā)表于 04-30 16:16 ?1865次閱讀
    HarmonyOS開發(fā)案例:【排行榜頁面】

    鴻蒙ArkUI開發(fā)實(shí)戰(zhàn):制作一個(gè)【簡(jiǎn)單計(jì)數(shù)器】

    ,?`@State`?是一個(gè)狀態(tài)標(biāo)識(shí)符,當(dāng)它修飾的變量值改變時(shí)ArkUI開發(fā)框架會(huì)調(diào)用?`build()`?方法進(jìn)行頁面的刷新。
    的頭像 發(fā)表于 04-08 18:05 ?559次閱讀
    鴻蒙ArkUI開發(fā)實(shí)戰(zhàn):制作一個(gè)【簡(jiǎn)單計(jì)數(shù)器】

    請(qǐng)問CortexM3中secure fault的lazy state指的是什么?

    正如題目所言,lazy state是一種什么狀態(tài)?
    發(fā)表于 03-18 06:10

    鴻蒙開發(fā)—【擴(kuò)展textinput組件

    %\'; //組件內(nèi)邊距 @State leftRightPadding:number = 16; @State topBottomPadding:number = 6; @State
    發(fā)表于 02-26 16:43

    Harmony 鴻蒙頁面級(jí)變量的狀態(tài)管理

    @State裝飾的變量是組件內(nèi)部的狀態(tài)數(shù)據(jù),當(dāng)這些狀態(tài)數(shù)據(jù)被修改時(shí),將會(huì)調(diào)用所在組件的build方法進(jìn)行UI刷新。 @State狀態(tài)數(shù)據(jù)具
    的頭像 發(fā)表于 01-25 10:42 ?540次閱讀
    Harmony 鴻蒙頁面級(jí)變量的狀態(tài)管理

    Harmony 鴻蒙頁面級(jí)變量的狀態(tài)管理

    @State裝飾的變量是組件內(nèi)部的狀態(tài)數(shù)據(jù),當(dāng)這些狀態(tài)數(shù)據(jù)被修改時(shí),將會(huì)調(diào)用所在組件的build方法進(jìn)行UI刷新。 @State狀態(tài)數(shù)據(jù)具
    發(fā)表于 01-24 20:04

    M480芯片tri-state指的是什么模式??

    as tri-state and open-drain mode The independent pull-down control register only valid when MODEn set
    發(fā)表于 01-16 06:38

    鴻蒙開發(fā)OpenHarmony組件復(fù)用案例

    組件。 我們創(chuàng)建的可復(fù)用組件有一個(gè)狀態(tài)變量@State item,構(gòu)造該自定義組件時(shí),父組件會(huì)給子母件傳遞構(gòu)造數(shù)據(jù)。 還需要實(shí)現(xiàn)
    發(fā)表于 01-15 17:37

    led屏亮度和刷新率的關(guān)系 led屏刷新率高低有什么影響

    led屏亮度和刷新率的關(guān)系 led屏刷新率高低有什么影響? LED顯示屏已成為了現(xiàn)代生活中不可或缺的一部分,其廣泛應(yīng)用于大型活動(dòng)、商業(yè)廣告、電視和計(jì)算機(jī)等領(lǐng)域。然而,很少有人深入了解LED屏亮度
    的頭像 發(fā)表于 12-11 17:07 ?2759次閱讀

    商用尺寸鈣鈦礦組件效率再創(chuàng)新高!

    極電光能曾先后4次刷新鈣鈦礦組件效率的世界紀(jì)錄,目前是810cm2小試組件及1.2x0.6m2商用尺寸鈣鈦礦組件效率的世界紀(jì)錄保持者。極電光能是行業(yè)內(nèi)第一個(gè)將鈣鈦礦
    的頭像 發(fā)表于 11-27 17:50 ?834次閱讀
    商用尺寸鈣鈦礦<b class='flag-5'>組件</b>效率再創(chuàng)新高!