Flutter狀態(tài)管理Provider(一)

? ? ? ?Google2019I/O大會上被谷歌推薦感挥,原本谷歌的provide被棄用缩搅,與大部分狀態(tài)管理一樣使用了InheritedWidget〈ビ祝基于Provider3.0
第二篇Flutter狀態(tài)管理Provider(二)

Provider()

兩種方式Provider()和Provider.value()硼瓣,使用基本差不多,區(qū)別在于Provider()提供dispose參數(shù)置谦,可以在傳遞一個方法銷毀的時候被調(diào)用堂鲤,方便StatelessWidget釋放資源,使用Provider寫一個bloc


1794647-cf4839d4dccb3bab_gaitubao_300x555.gif
import 'dart:async';

class CountBloc {
  final StreamController<int> _countController = StreamController();
  int count = 0;
  Stream<int> stream;

  CountBloc() {
    stream = _countController.stream.asBroadcastStream();
  }

  add() {
    _countController.add(++count);
  }

  //關閉
  dispose() {
    _countController?.close();
  }
}

界面代碼

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'count_bloc.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    //如果狀態(tài)管理放在頂層 MaterialApp 之上媒峡,它的作用域是全局瘟栖,任何界面都可以獲取;
    return Provider<CountBloc>(
      builder: (context) => CountBloc(),
      //dispose:在widget銷毀的時候調(diào)用,方便關閉stream丝蹭,可以防止內(nèi)存泄露
      //特別是在在StatelessWidget中使用非常好慢宗,因為StatelessWidget沒有dispose方法
      dispose: (context, value) => value.dispose(),
      child: MaterialApp(
        title: "provider",
        home: HomePage(),
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("HomePage")),
      body: StreamBuilder(
          stream: Provider.of<CountBloc>(context).stream,
          initialData: 0,
          builder: (context, snapshot) {
            return Center(child: Text("${snapshot.data}"));
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => SecondPage()));
        },
        child: Icon(Icons.arrow_forward_ios),
      ),
    );
  }
}

class SecondPage extends StatefulWidget {
  @override
  _SecondPageState createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
  @override
  Widget build(BuildContext context) {
    CountBloc bloc = Provider.of<CountBloc>(context);
    return Scaffold(
      appBar: AppBar(title: Text("第二頁")),
      body: StreamBuilder(
          stream: bloc.stream,
          initialData: bloc.count,
          builder: (context, snapshot) {
            return Center(child: Text("${snapshot.data}"));
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () => bloc.add(),
        child: Icon(Icons.add),
      ),
    );
  }
}
  1. 下面使用ValueListenableProvider,它只支持單一數(shù)據(jù)的監(jiān)聽奔穿,有兩種方式镜沽,一種ValueListenableProvider.value(),另一種ValueListenableProvider()贱田,兩種方式幾乎是相同的缅茉。
    先介紹下Consumer和Provider:
//此方法將從BuildContext關聯(lián)的小部件樹中查找,它將返回找到的最近的類型變量T
Provider.of<T>( BuildContext context,
     {bool listen = true}//listen:默認true監(jiān)聽狀態(tài)變化男摧,false為不監(jiān)聽狀態(tài)改變
)
//也可以使用Consumer組件獲取蔬墩,Consumer可用在沒有context的地方,還可以優(yōu)化性能
Consumer<T>({
    @required this.builder,//這邊寫布局
    this.child,//可以控制刷新性能優(yōu)化耗拓,當數(shù)據(jù)數(shù)據(jù)發(fā)生改變拇颅,不會重新build,
  })
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "provider",
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ValueNotifier<int> count = ValueNotifier(0);
    //在HomePage里面寫狀態(tài)乔询,它的作用域只在HomePage中
    return Scaffold(
      appBar: AppBar(title: Text("home")),
      body: ValueListenableProvider.value(
        value: count,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            LeftView(), CenterView(), RightView()
          ],
        ),
      ),
      floatingActionButton:
          FloatingActionButton(onPressed: () => count.value += 1,child: Icon(Icons.add),),
    );
  }
}

class LeftView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("LeftView:build");
    return Consumer<int>(
        child: MyText(),
        builder: (context, value, child) {
          return Container(
              width: 100,
              height: 100,
              color: Colors.blue,
              alignment: Alignment.center,
              child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[child, Text("$value")]));
        });
  }
}

class MyText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("MyText:build");
    return Text("數(shù)量");
  }
}

class CenterView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("CenterView:build");
    return Container(
      width: 100,
      height: 100,
      color: Colors.pink,
      alignment: Alignment.center,
      child: Text(
        //listen: false 不監(jiān)聽狀態(tài)改變
        "數(shù)量\n${Provider.of<int>(context, listen: false)}",
        textAlign: TextAlign.center,
      ),
    );
  }
}

class RightView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("RightView:build");
    return Container(
      width: 100,
      height: 100,
      color: Colors.green,
      alignment: Alignment.center,
      child: Text(
        "數(shù)量\n${Provider.of<int>(context)}",
        textAlign: TextAlign.center,
      ),
    );
  }
}
1794647-31a67f0a79b6b742_gaitubao_300x801.gif

1樟插、觀察日志發(fā)現(xiàn)藍色LeftView和MyText初始化后沒有重新build。
2竿刁、紅色CenterView初始化后也沒有重新build
3黄锤、綠色RightView會隨著狀態(tài)改變會重新build
總結使用Consumer可以有效的優(yōu)化性能,使用ValueListenableProvider時Provider.of<T>()獲取部件樹中狀態(tài)同時也可以監(jiān)聽狀態(tài)改變從而刷新部件食拜。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸵熟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子负甸,更是在濱河造成了極大的恐慌流强,老刑警劉巖痹届,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異打月,居然都是意外死亡短纵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門僵控,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鱼冀,你說我怎么就攤上這事报破。” “怎么了千绪?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵充易,是天一觀的道長。 經(jīng)常有香客問我荸型,道長盹靴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任瑞妇,我火速辦了婚禮稿静,結果婚禮上,老公的妹妹穿的比我還像新娘辕狰。我一直安慰自己改备,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布蔓倍。 她就那樣靜靜地躺著悬钳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪偶翅。 梳的紋絲不亂的頭發(fā)上默勾,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音聚谁,去河邊找鬼母剥。 笑死,一個胖子當著我的面吹牛垦巴,可吹牛的內(nèi)容都是我干的媳搪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼骤宣,長吁一口氣:“原來是場噩夢啊……” “哼秦爆!你這毒婦竟也來了?” 一聲冷哼從身側響起憔披,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤等限,失蹤者是張志新(化名)和其女友劉穎爸吮,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體望门,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡形娇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了筹误。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桐早。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖厨剪,靈堂內(nèi)的尸體忽然破棺而出哄酝,到底是詐尸還是另有隱情,我是刑警寧澤祷膳,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布陶衅,位于F島的核電站,受9級特大地震影響直晨,放射性物質(zhì)發(fā)生泄漏搀军。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一勇皇、第九天 我趴在偏房一處隱蔽的房頂上張望罩句。 院中可真熱鬧,春花似錦儒士、人聲如沸的止。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诅福。三九已至,卻和暖如春拖叙,著一層夾襖步出監(jiān)牢的瞬間氓润,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工薯鳍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留咖气,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓挖滤,卻偏偏與公主長得像崩溪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子斩松,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

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