Flutter 46: 圖解新的狀態(tài)管理 Provider (一)

??????2019 Google I/O 大會(huì)上重磅消息出了支持 flutter_web 之外,另一個(gè)便是棄用之前的狀態(tài)管理 Provide,轉(zhuǎn)而推薦相似的庫 Provider具帮;雖然只有一個(gè)字母之差使用方式差別卻很大;小菜初步學(xué)習(xí)一下新的狀態(tài)管理庫 Provider

??????Flutter 針對(duì)不同類型對(duì)象提供了多種不同的 Provider滋饲;Provider 也是借助了 InheritWidget,將共享狀態(tài)放到頂層 MaterialApp 之上;

Provider 方式

??????最基本的狀態(tài)管理方式喊巍,以一個(gè)參數(shù)方式綁定和展示屠缭;

1. 綁定數(shù)據(jù)

??????Provider 可在需要的 Widget 處進(jìn)行數(shù)據(jù)綁定:

const Provider.value({
    Key key,
    @required T value,
    this.updateShouldNotify,
    this.child,
})  : dispose = null,
        super.value(key: key, value: value);

??????分析源碼 Provider.value 并沒有限制 value 類型,我們可以根據(jù)需求隨意綁定需要的數(shù)據(jù)類型崭参;當(dāng)我們確定綁定的數(shù)據(jù)類型時(shí)呵曹,建議綁定時(shí)添加數(shù)據(jù)類型,如:Provider<String>.value( value: '', child:)何暮;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: Provider<String>.value( value: 'FirstPage Provider', child: MyHomePage(title: 'Peovider Demo')));
  }
}

2. 獲取數(shù)據(jù)

??????Provider 需要在數(shù)據(jù)綁定的子 Widget 中進(jìn)行獲妊傥埂;使用靜態(tài)方法 Provider.of<T>(BuildContext context)海洼,此方法從 BuildContext 關(guān)聯(lián)的 Widget Tree 中查找最近的相同類型的數(shù)據(jù)進(jìn)行展示跨新;沒有則報(bào)異常;

Text('${Provider.of<String>(context)}'),
Text('FirstPage Provider: ${Provider.of<String>(context)} | ${Provider.of<int>(context)} | ${Provider.of<bool>(context)}}'),

3. 綁定多條數(shù)據(jù)

??????在我們實(shí)際開發(fā)中不會(huì)只綁定一條數(shù)據(jù)坏逢,當(dāng)綁定多條數(shù)據(jù)時(shí)可以采用如下兩種方式:嵌套綁定和聚合綁定域帐;兩種方式效果完全相同,小菜更傾向于 MultiProvider 綁定是整,層級(jí)更清晰簡(jiǎn)潔肖揣;

// 嵌套綁定
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: Provider<User>.value(
            value: new User('Flutter', 300),
            child: Provider<int>.value(
                value: 200,
                child: Provider<bool>.value(
                    value: false, child: MyHomePage(title: 'Peovider Demo')))));
  }
}

// 聚合方式
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: MultiProvider(providers: [
          Provider<User>.value(value: new User('Flutter', 300)),
          Provider<int>.value(value: 200),
          Provider<bool>.value(value: false)
        ], child: MyHomePage(title: 'Peovider Demo')));
  }
}

4. 綁定數(shù)據(jù)類型

??????Provider 綁定數(shù)據(jù)類型比較靈活,并非只是基本數(shù)據(jù)類型浮入,小菜定義了一個(gè) User 類龙优,可正常狀態(tài)管理;小菜在獲取 User 后重新設(shè)置 name 之后獲取的 User 為最新的數(shù)據(jù)舵盈;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: MultiProvider(providers: [
          Provider<User>.value(value: new User('Flutter', 300)),
          Provider<int>.value(value: 200),
          Provider<bool>.value(value: false)
        ], child: MyHomePage(title: 'Peovider Demo')));
  }
}

Text(
    'FirstPage Provider: ${Provider.of<String>(context)} | '
    '${Provider.of<int>(context)} | ${Provider.of<bool>(context)} | ${Provider.of<User>(context).name = 'Hello World!'}',
    style: TextStyle(color: Colors.redAccent)),
Text('${Provider.of<User>(context).name}'),

5. 作用域

??????小菜在剛開始學(xué)習(xí)時(shí)被作用域卡到陋率,實(shí)際文檔說的很明白,獲取綁定數(shù)據(jù)的范圍是在綁定數(shù)據(jù)的子 Widget 中秽晚;小菜繪制了一下個(gè)人理解的基本作用域圖瓦糟,如有錯(cuò)誤請(qǐng)多多指導(dǎo);

??????void main() => runApp() 為范圍最廣的 application 作用域赴蝇,其作用范圍包括各個(gè) Page 之間菩浙;FirstPage 中定義的 Provider A 作用在藍(lán)色框范圍內(nèi),Provider B 作用在粉色框范圍內(nèi),SecondPage 中定義的 Provider C 作用在綠色范圍內(nèi)劲蜻;超出范圍則不能進(jìn)行狀態(tài)管理陆淀;

6. 作用域內(nèi)容

??????如上圖作用域劃分,在 FirstPage 多個(gè)作用域的粉色框中先嬉,若獲取 String 類型的狀態(tài)管理 Provider<String>.value( value: '', child:)轧苫,首先在粉色作用域中查找,若存在則展示粉色框中綁定數(shù)據(jù)疫蔓;若沒有則查找上一層藍(lán)色作用域含懊,存在則為藍(lán)色框綁定數(shù)據(jù);若依然沒有查找 application 作用域衅胀,存在則展示 application 作用域綁定數(shù)據(jù)岔乔;若均沒有則報(bào)異常;

??????這也驗(yàn)證了文檔中提及的子 Widget 作用域滚躯,一層一層往外層查找雏门,直到可以正常獲取掸掏;

ChangeNotifierProvider 方式

??????通過調(diào)用 ChangeNotifier.notifyListeners 對(duì) ChangeNotifier 進(jìn)行監(jiān)聽茁影,將其公開給它的子 Widget 并重建依賴項(xiàng);

1. 綁定數(shù)據(jù)

ChangeNotifierProvider 綁定數(shù)據(jù)有兩種方式:

  1. ChangeNotifierProvider({Key key, @required ValueBuilder<T> builder, Widget child })

??????通過構(gòu)造器創(chuàng)建一個(gè) ChangeNotifier阅束,在 ChangeNotifierProvider 移除時(shí)自動(dòng)處理呼胚;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<User>(
        builder: (_) => User('Flutter', 0),
        child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.blue),
            home: MyHomePage(title: 'Peovider Demo')));
  }
}
  1. ChangeNotifierProvider.value({Key key, @required T notifier, Widget child })

??????通過監(jiān)聽通知給子 Widget 并重建依賴項(xiàng);

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<User>.value(
        notifier: User('Flutter', 0),
        child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.blue),
            home: MyHomePage(title: 'Peovider Demo')));
  }
}

2. 獲取數(shù)據(jù)

??????獲取數(shù)據(jù)的方式與直接使用 Provider 相似息裸;

Text('${Provider.of<User>(context).getName}'),

??????相對(duì)于 Provider蝇更,ChangeNotifierProvider 方式更加靈活,可以通過重寫 get/set 方法來對(duì)狀態(tài)管理進(jìn)行修改和使用呼盆;

// User 實(shí)體 Bean
class User with ChangeNotifier {
  var name;
  var age;

  User(this.name, this.age);

  void setName(String name) {
    this.name = name;
    notifyListeners();
  }

  String get getName => this.name;
}
// 綁定 Provider
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<User>(
        builder: (_) => User('Flutter', 0),
        child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.blue),
            home: MyHomePage(title: 'Peovider Demo')));
  }
}
// 獲取 Provider 數(shù)據(jù)
Expanded(
    child: TextField(
        onChanged: (changed) =>
            Provider.of<User>(context).setName(changed),
        controller: _phonecontroller,
        decoration: InputDecoration(
            hintText: '請(qǐng)輸入用戶名',
            suffixIcon: IconButton(
                icon: Icon(Icons.clear,
                    color: Colors.black45),
                onPressed: () {
                  _phonecontroller.clear();
                })))),
Text('${Provider.of<User>(context).getName}'),

問題小結(jié)

??????小菜在開始嘗試時(shí)總是遇到如下問題年扩,Could not find the correct Provider... 測(cè)試后了解是在子 Widget 中層級(jí)查找未找到對(duì)應(yīng)的綁定數(shù)據(jù);極有可能是綁定數(shù)據(jù)的 Widget 位置未綁定或綁定位置錯(cuò)誤访圃;


??????小菜對(duì) Provider 的理解還很淺顯厨幻,對(duì)于其他 Provider 的使用還未嘗試;如有錯(cuò)誤請(qǐng)多多指導(dǎo)腿时!

來源:阿策小和尚

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末况脆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子批糟,更是在濱河造成了極大的恐慌格了,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徽鼎,死亡現(xiàn)場(chǎng)離奇詭異盛末,居然都是意外死亡弹惦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門悄但,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棠隐,“玉大人,你說我怎么就攤上這事檐嚣≈螅” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵净嘀,是天一觀的道長(zhǎng)报咳。 經(jīng)常有香客問我侠讯,道長(zhǎng)挖藏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任厢漩,我火速辦了婚禮膜眠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘溜嗜。我一直安慰自己宵膨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布炸宵。 她就那樣靜靜地躺著辟躏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪土全。 梳的紋絲不亂的頭發(fā)上捎琐,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音裹匙,去河邊找鬼瑞凑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛概页,可吹牛的內(nèi)容都是我干的籽御。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼惰匙,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼技掏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起项鬼,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤哑梳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后秃臣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涧衙,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哪工,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年抄沮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怜跑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蕊梧。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唯蝶,死狀恐怖脐彩,靈堂內(nèi)的尸體忽然破棺而出窃诉,到底是詐尸還是另有隱情啤咽,我是刑警寧澤讳癌,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布序攘,位于F島的核電站茴她,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏程奠。R本人自食惡果不足惜丈牢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞄沙。 院中可真熱鬧己沛,春花似錦、人聲如沸距境。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垫桂。三九已至师幕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诬滩,已是汗流浹背霹粥。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碱呼,地道東北人蒙挑。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像愚臀,于是被迫代替她去往敵國和親忆蚀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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

  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程姑裂,因...
    小菜c閱讀 6,358評(píng)論 0 17
  • 簡(jiǎn)介 用簡(jiǎn)單的話來定義tcpdump馋袜,就是:dump the traffic on a network,根據(jù)使用者...
    保川閱讀 5,941評(píng)論 1 13
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 烏云布滿天舶斧,氣悶熱如煙欣鳖。 只盼飛來雨,涼風(fēng)把夢(mèng)穿茴厉。 ——平水韻 平起首句押韻
    原野騎兵閱讀 722評(píng)論 4 14
  • 印發(fā)來消息,“我剛剛是哭著來找你的怀酷,就是一直哭稻爬,我這個(gè)人,真是軟用沒有蜕依,遇到點(diǎn)事情就哭桅锄,還特別懶,長(zhǎng)相比不上好看的...
    醉酒少年閱讀 263評(píng)論 0 1