Flutter状态管理Provider

链接:https://www.jianshu.com/p/93e97fd0f298


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';voidmain()=>runApp(MyApp());classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){//MultiProvider可以添加多个状态管理//包裹在MaterialApp外面,作用范围是全局returnMultiProvider(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';classIndexPageextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){returnConsumer(//优化:在状态改变时viewpage子页面不会走build方法child:PageView(physics:NeverScrollableScrollPhysics(),//禁止滚动//获取pageController后不监听改变controller:Provider.of(context,listen:false).pageController,children:[ChildPage("第一页"),ChildPage("第二页"),ChildPage("第三页")],),builder:(context,indexProvider,child){returnScaffold(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()));}),);});}}classChildPageextendsStatefulWidget{finalString title;ChildPage(this.title);@override_ChildPageStatecreateState()=>_ChildPageState();}class_ChildPageStateextendsStatewithAutomaticKeepAliveClientMixin{@overrideboolgetwantKeepAlive=>true;@overridevoidinitState(){super.initState();print("${widget.title}: initState");}@overrideWidgetbuild(BuildContext context){super.build(context);print("${widget.title}: build");returnScaffold(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)),);}}classSecondPageextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(),body:Center(child:Row(mainAxisSize:MainAxisSize.max,mainAxisAlignment:MainAxisAlignment.center,children:[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(context,listen:false).index=index;}}

import'package:flutter/material.dart'show ChangeNotifier,PageController;classIndexProviderwithChangeNotifier{int _index=0;PageController pageController;intgetindex=>_index;setindex(int value){_index=value;pageController.jumpToPage(this._index);notifyListeners();}IndexProvider(){pageController=PageController(initialPage:_index);}//使用ChangeNotifierProvider会在销毁时调用dispose()方法释放资源@overridevoiddispose(){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()

classStreamPageextendsStatefulWidget{@override_StreamPageStatecreateState()=>_StreamPageState();}class_StreamPageStateextendsState{StreamController _streamController;int _count=4;@overridevoidinitState(){super.initState();_streamController=StreamController();}@overridevoiddispose(){_streamController.close();super.dispose();}@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(title:Text("StreamProvider")),//      body: StreamProvider.value(//        value: _streamController.stream,//        initialData: _count,////        catchError: ,//        child: MyText(),//      ),body:StreamProvider(builder:(_)=>_streamController.stream,//builder等于valueinitialData:_count,//initialData:初始化时的值,不写为nullcatchError:(BuildContext context,Object error){//catchError:异常时调用,返回值与StreamController范型一样//如果catchError不写,当报错时屏幕直接爆红出错print("哈哈:${error.toString()}");return10000;},child:MyText(),),floatingActionButton:FloatingActionButton(onPressed:(){if(_count<8)_streamController.sink.add(++_count);else_streamController.sink.addError("异常啦");},child:Icon(Icons.add),),);}}classMyTextextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){finalcount=Provider.of(context);returnCenter(child:Text("$count"));}}

StreamProvider.controller()代码:

classStreamPageextendsStatefulWidget{@override_StreamPageStatecreateState()=>_StreamPageState();}class_StreamPageStateextendsState{StreamController _streamController;int _count=4;@overridevoidinitState(){super.initState();_streamController=StreamController();}@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(title:Text("StreamProvider")),body:StreamProvider.controller(builder:(_)=>_streamController,initialData:_count,//initialData:初始化时的值,不写为nullcatchError:(BuildContext context,Object error){//catchError:异常时调用,返回值与StreamController范型一样//如果catchError不写,当报错时屏幕直接爆红出错print("哈哈:${error.toString()}");return10000;},child:MyText(),),floatingActionButton:FloatingActionButton(onPressed:(){if(_count<8)_streamController.sink.add(++_count);else_streamController.sink.addError("异常啦");//手动抛异常},child:Icon(Icons.add),),);}}classMyTextextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){finalcount=Provider.of(context);returnCenter(child:Text("$count"));}}

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

进入源码可以看到

StreamProvider.controller.png

StreamControllerBuilderDelegate.png

总结:

Provider()与Provider.value()区别是Provider()有一个dispose参数传递一个方法可以帮助我们销毁的时候释放资源,它们都不提供状态改变监听。

ValueListenableProvider.value()与ValueListenableProvider()是差不多的,只支持一个状态值。

ChangeNotifierProvider.value()与ChangeNotifierProvider()区别是ChangeNotifierProvider()在销毁的时候调用dispose()释放资源,在需要使用多个状态值时可以使用ChangeNotifierProvider。

ListenableProvider代码没有写出来,它是ChangeNotifierProvider的父类,

ListenableProvider.value()和ChangeNotifierProvider.value()功能一样,ListenableProvider()与ValueListenableProvider()差不多,但ListenableProvider()多了一个dispose参数,需要自己传,在销毁的时候调用释放资源.

StreamProvider.value()和StreamProvider()基本一样,都需要手动关闭流,而StreamProvider.controller()自动关闭流。

MultiProvider()可以提供多个状态。

Provider.of()用来获取Widget树中的状态,在使用 ValueListenableProvider、ChangeNotifierProvider和StreamProvider时Provider.of()中的listen参数可以控制是否监听状态改变。

Consumer()与Provider.of()都是用来获取Widget树中的状态,但Consumer可以用在没有context的地方,也可以用来优化性能,使用child参数可以缩小重绘的范围。

状态管理包裹在MaterialApp()外面作用域是全局,其他作用域在本页面或本页的子Widget中;

如有写的不对的地方欢迎指出!

作者:简wen

链接:https://www.jianshu.com/p/93e97fd0f298

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(Flutter状态管理Provider)