Flutter状态管理Provider

Google2019I/O大会上被谷歌推荐,原本谷歌的provide被弃用,与大部分状态管理一样使用了InheritedWidget。基于Provider3.0
上一篇Flutter状态管理Provider(一)

ChangeNotifierProvider()

       它与scoped_model差不多,不同的是它使用mixin而scoped_model使用的继承,首先状态类mixin一个ChangeNotifier,然后通过调用notifyListeners()来通知状态更新。
       和ValueListenableProvider一样也有两种方式,ChangeNotifierProvider()和ChangeNotifierProvider.value(),区别在于ChangeNotifierProvider()会在销毁时自动调用ChangeNotifier中的dispose()方法释放一些资源。
       下面使用ChangeNotifierProvider()写一个需求,与微信一样底部4个按钮切换界面,然后跳到二级页面点击二级页面按钮控制一级页面的切换,先上图:

 

sp.2019-06-27 18_11_16.gif

下面上代码:

 

import "package:flutter/material.dart";
import 'index_page.dart';
import 'package:provider/provider.dart';
import 'index_provider.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //MultiProvider可以添加多个状态管理
    //包裹在MaterialApp外面,作用范围是全局
    return MultiProvider(
      providers: [
//      两种方式,这里使用ChangeNotifierProvider,因为可以自动调用dispose()方法,帮我释放资源
        ChangeNotifierProvider(builder: (_) => IndexProvider()),
//        ChangeNotifierProvider.value(value: IndexProvider())
      ],
      child: MaterialApp(
        title: "Flutter Demo",
        theme: ThemeData(primarySwatch: Colors.blue),
        home: IndexPage(),
      ),
    );
  }
}

 

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

class IndexPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<IndexProvider>(
        //优化:在状态改变时viewpage子页面不会走build方法
        child: PageView(
          physics: NeverScrollableScrollPhysics(), //禁止滚动
          //获取pageController后不监听改变
          controller: Provider.of<IndexProvider>(context,listen: false).pageController,
          children: [ChildPage("第一页"), ChildPage("第二页"), ChildPage("第三页")],
        ),
        builder: (context, indexProvider, child) {
          return Scaffold(
            body: child,
            bottomNavigationBar: BottomNavigationBar(
                onTap: (index) {
                  indexProvider.index = index;
                },
                currentIndex: indexProvider.index,
                items: [
                  BottomNavigationBarItem(icon: Icon(Icons.android), title: Text("android")),
                  BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("home")),
                  BottomNavigationBarItem(icon: Icon(Icons.person), title: Text("person")),
                ]),
            floatingActionButton: FloatingActionButton(onPressed: () {
              Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage()));
            }),
          );
        });
  }
}

class ChildPage extends StatefulWidget {
  final String title;

  ChildPage(this.title);

  @override
  _ChildPageState createState() => _ChildPageState();
}

class _ChildPageState extends State<ChildPage> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  void initState() {
    super.initState();
    print("${widget.title}: initState");
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    print("${widget.title}: build");
    return Scaffold(
      backgroundColor: widget.title == '第一页'
          ? Colors.red.withOpacity(0.5)
          : widget.title == '第二页'
          ? Colors.yellow.withOpacity(0.5)
          : Colors.green.withOpacity(0.5),
      appBar: AppBar(title: Text(widget.title)),
      body: Center(child: Text(widget.title)),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FlatButton(onPressed: () => changePageIndex(context, 0), child: Text("切换1"), color: Colors.red),
            FlatButton(onPressed: () => changePageIndex(context, 1), child: Text("切换2"), color: Colors.yellow),
            FlatButton(onPressed: () => changePageIndex(context, 2), child: Text("切换3"), color: Colors.green),
          ],
        ),
      ),
    );
  }

  changePageIndex(context, int index) {
    Provider.of<IndexProvider>(context, listen: false).index = index;
  }
}

 

import 'package:flutter/material.dart' show ChangeNotifier, PageController;

class IndexProvider with ChangeNotifier {
  int _index = 0;
  PageController pageController;

  int get index => _index;

  set index(int value) {
    _index = value;
    pageController.jumpToPage(this._index);
    notifyListeners();
  }

  IndexProvider() {
    pageController = PageController(initialPage: _index);
  }

  //使用ChangeNotifierProvider会在销毁时调用dispose()方法释放资源
  @override
  void dispose() {
    pageController?.dispose();
    super.dispose();
  }
}

 

 

源码

ChangeNotifierProvider.png

StreamProvider

       它有三种使用方式,StreamProvider、StreamProvider.value()和StreamProvider.controller(),StreamProvider和StreamProvider.value()几乎一样,StreamProvider.controller()有一点不一样,先上图:

 

aaaaaa.2019-06-27 18_15_11.gif

 

先介绍StreamProvider和StreamProvider.value()

 

class StreamPage extends StatefulWidget {
  @override
  _StreamPageState createState() => _StreamPageState();
}

class _StreamPageState extends State<StreamPage> {
  StreamController _streamController;
  int _count=4;

  @override
  void initState() {
    super.initState();
    _streamController = StreamController<int>();
  }

  @override
  void dispose() {
    _streamController.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("StreamProvider")),
//      body: StreamProvider<int>.value(
//        value: _streamController.stream,
//        initialData: _count,
        catchError: ,
//        child: MyText(),
//      ),
      body: StreamProvider<int>(
        builder: (_) => _streamController.stream,//builder等于value
        initialData: _count,//initialData:初始化时的值,不写为null
        catchError: (BuildContext context, Object error) {
          //catchError:异常时调用,返回值与StreamController范型一样
          //如果catchError不写,当报错时屏幕直接爆红出错
          print("哈哈:${error.toString()}");
          return 10000;
        },
        child: MyText(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if(_count<8) _streamController.sink.add(++_count);
          else _streamController.sink.addError("异常啦");
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class MyText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final count = Provider.of<int>(context);
    return Center(child: Text("$count"));
  }
}

StreamProvider<T>.controller()代码:

 

class StreamPage extends StatefulWidget {
  @override
  _StreamPageState createState() => _StreamPageState();
}

class _StreamPageState extends State<StreamPage> {
  StreamController _streamController;
  int _count = 4;

  @override
  void initState() {
    super.initState();
    _streamController = StreamController<int>();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("StreamProvider")),
      body: StreamProvider<int>.controller(
        builder: (_) => _streamController,
        initialData: _count, //initialData:初始化时的值,不写为null
        catchError: (BuildContext context, Object error) {
          //catchError:异常时调用,返回值与StreamController范型一样
          //如果catchError不写,当报错时屏幕直接爆红出错
          print("哈哈:${error.toString()}");
          return 10000;
        },
        child: MyText(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_count < 8)
            _streamController.sink.add(++_count);
          else
            _streamController.sink.addError("异常啦");//手动抛异常
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class MyText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final count = Provider.of<int>(context);
    return Center(child: Text("$count"));
  }
}

       嗯?!看上去好像没什么不同,但你仔细看StreamProvider<T>.controller代码里面我没有重写dispose()方法,原因是StreamProvider<T>.controller会帮我们在销毁是调用StreamController的close()方法。
进入源码可以看到

 

StreamProvider.controller.png

 

StreamControllerBuilderDelegate.png

总结:

  1. Provider()与Provider.value()区别是Provider()有一个dispose参数传递一个方法可以帮助我们销毁的时候释放资源,它们都不提供状态改变监听。
  2. ValueListenableProvider.value()与ValueListenableProvider()是差不多的,只支持一个状态值。
  3. ChangeNotifierProvider.value()与ChangeNotifierProvider()区别是ChangeNotifierProvider()在销毁的时候调用dispose()释放资源,在需要使用多个状态值时可以使用ChangeNotifierProvider。
  4. ListenableProvider代码没有写出来,它是ChangeNotifierProvider的父类,
    ListenableProvider.value()和ChangeNotifierProvider.value()功能一样,ListenableProvider()与ValueListenableProvider()差不多,但ListenableProvider()多了一个dispose参数,需要自己传,在销毁的时候调用释放资源.
  5. StreamProvider.value()和StreamProvider()基本一样,都需要手动关闭流,而StreamProvider.controller()自动关闭流。
  6. MultiProvider()可以提供多个状态。
  7. Provider.of<T>()用来获取Widget树中的状态,在使用 ValueListenableProvider、ChangeNotifierProvider和StreamProvider时Provider.of<T>()中的listen参数可以控制是否监听状态改变。
  8. Consumer<T>()与Provider.of<T>()都是用来获取Widget树中的状态,但Consumer可以用在没有context的地方,也可以用来优化性能,使用child参数可以缩小重绘的范围。
  9. 状态管理包裹在MaterialApp()外面作用域是全局,其他作用域在本页面或本页的子Widget中;



作者:简wen
链接:https://www.jianshu.com/p/93e97fd0f298
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值