本文章就不对StreamBuilder过多的介绍了,如果不了解的可以去这篇文章中先行了解一下
https://www.jianshu.com/p/889ea7f9734a
关于StreamBuilder,我们常用来做的就是异步加载WidgetUI,为了使整个项目做到统一的规范化,我们将封装一个统一的StreamBuilder,用来全局使用。
大体分为以下几个文件
他们分别的作用是
GlobalState
:全局状态管理
mult_state
:返回控件Widget
StateMangage
:StreamController的控制器
streamBuilder
:我们要展示的Widget页面
进入正题
一、streamBuilder
我们首先要做的肯定要创建出来展示给页面的Widget,由于是动态数据页面,所以创建的时候我们可以使用statefulWidget
,接口数据使用的是豆瓣电影
的数据,在这里使用了dio
做请求处理,当然在写dio
请求的时候,我们可以适当的传进去个参数,用来控制请求是否抛出异常
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
class StreamBuilderPage extends StatefulWidget {
@override
_StreamBuilderPageState createState() => _StreamBuilderPageState();
}
class _StreamBuilderPageState extends State<StreamBuilderPage> {
Future _loadData(bool needException) async{
Response response =await Dio().get('https://douban.uieee.com/v2/movie/in_theaters');
// 按需设置返回异常
if(needException){
return Future.error('请求错误');
}
if(response.statusCode == 200){
return response.data;
}else{
return Future.error('请求错误');
}
}
@override
void initState() {
super.initState();
_loadData(false).then((val){
print(val)
}).catchError((err){
print(err)
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('封装StreamBuilder'),),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh),
onPressed: _loadNetData,
),
);
}
}
二、GlobalState
创建一个全局的状态管理,根据不同的状态,来返回不同状态的控件
这里所说的全局状态管理,其实也只是针对StreamBuilder渲染出来的Widget来管理状态,也只能管理要渲染出来的那个Widget
class GlobalState{}
class GlobalLoadingState extends GlobalState{}
class GlobalErrorState extends GlobalState{}
class GlobalHideDialogState extends GlobalState{}
// 为了全局APP都能使用这个状态,所以传入一个泛型,这样任何类型数据进来,都能接收
class GlobalContentState<T> extends GlobalState{
T t;
GlobalContentState(this.t);
}
三、
创建一个Stream控制类并实例化,这样我们每一次调用该类,都会创建一个新的StreamController
,在该类中封装好Stream的方法,一旦调用某个方法,就要sink
进去新的的状态类
import 'dart:async';
import 'package:jianzhi/page/encapsulationStream/GlobalState.dart';
// Stream的控制类
class StateManage{
StreamController<GlobalState> streamController;
StateManage(){
streamController = StreamController();
}
// 销毁
void dispose(){
if(streamController!=null){
streamController.close();
}
}
// loading状态时
void loading(){
streamController.sink.add(GlobalLoadingState());
}
void error(){
streamController.sink.add(GlobalErrorState());
}
void content<T>(T t){
streamController.sink.add(GlobalContentState(t));
}
}
四、mult_state
完成上面的后,我们已经有了展示给用户的Widget以及全局控制的State状态,接下来,我们开始写一个全局可用的专门用来返回Widget的文件,也就是上面提到的mult_state.dart
,这个文件外层就需要包裹着我们的StreamBuilder了,因为我们需要每一个返回的Widget都有Stream流的控制。代码中引入的loadingWidget只是简单的写了下,errorWidget也是一样的。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:jianzhi/page/AsyncWidget/errorWidget.dart';
import 'package:jianzhi/page/AsyncWidget/loadingWidget.dart';
import 'package:jianzhi/page/encapsulationStream/GlobalState.dart';
// 生成具体的Widget
// typedef
typedef GlobalContentBuilder<T> = Widget Function(BuildContext buildContext, T t);
// 返回各种状态下的Widget
// T是当前生成页面Widget的数据
class MultiState<T> extends StatefulWidget {
Widget loading = LoadingPage();
Widget error = ErrorPage();
GlobalContentBuilder contentBuilder;
StreamController<GlobalState> streamController;
// 接收传来的stream控制器、builder构造器
MultiState({this.streamController, this.contentBuilder, this.loading, this.error});
@override
_MultiStateState<T> createState() => _MultiStateState<T>();
}
class _MultiStateState<T> extends State<MultiState> {
@override
Widget build(BuildContext context) {
return Container(
child: StreamBuilder<GlobalState>(
stream: widget.streamController.stream,
builder: (context, snap){
Widget result;
if(snap.data != null){
if(snap.data is GlobalLoadingState){
result = LoadingPage();
}else if(snap.data is GlobalErrorState){
result = ErrorPage();
}else if(snap.data is GlobalContentState){
result = widget.contentBuilder(context, (snap.data as GlobalContentState).t);
}
}
// 这里必须返回一个空容器的,否则会报错
if(result == null){
result = Container();
}
return result;
},
),
);
}
}
五、
接下来就是回到我们一开始写的streamBuilder.dart
文件这里来调用了,当然还缺一个用来展示的WIdgetUI界面,在这里补上
Film.dart
import 'package:flutter/material.dart';
class FilmPage extends StatefulWidget {
final data;
const FilmPage({Key key, this.data}) : super(key: key);
@override
_FilmPageState createState() => _FilmPageState();
}
class _FilmPageState extends State<FilmPage> {
@override
void initState() {
super.initState();
print('${widget.data}');
}
@override
Widget build(BuildContext context) {
return Scaffold(
// appBar: AppBar(title: Text('豆瓣电影'),),
body: Container(
child: Column(
children: <Widget>[
Image.network('${widget.data['subjects'][0]['images']['small']}', fit: BoxFit.cover,),
Text('${widget.data['subjects'][0]['title']}')
],
),
),
);
}
}
完善后的streamBuilder.dart
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:jianzhi/page/encapsulationStream/StateManage.dart';
import 'package:jianzhi/page/encapsulationStream/mult_state.dart';
import 'package:jianzhi/page/pages/film.dart';
class StreamBuilderPage extends StatefulWidget {
@override
_StreamBuilderPageState createState() => _StreamBuilderPageState();
}
class _StreamBuilderPageState extends State<StreamBuilderPage> {
StateManage stateManage;
Future _loadData(bool needException) async{
Response response =await Dio().get('https://douban.uieee.com/v2/movie/in_theaters');
// 按需设置返回异常
if(needException){
return Future.error('请求错误');
}
if(response.statusCode == 200){
return response.data;
}else{
return Future.error('请求错误');
}
}
@override
void initState() {
stateManage = StateManage();
super.initState();
_loadNetData();
}
@override
void dispose() {
stateManage.dispose();
super.dispose();
}
void _loadNetData(){
stateManage.loadingDialog();
_loadData(false).then((val){
stateManage.content(val);
}).catchError((err){
stateManage.error();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('封装StreamBuilder'),),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh),
onPressed: _loadNetData,
),
body: MultiState(
streamController: stateManage.streamController,
contentBuilder: (context, data){
return FilmPage(data: data);
},
),
);
}
}