ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Flutter之StreamBuilder的封装,让你的项目更加工程化

2020-02-20 11:39:02  阅读:451  来源: 互联网

标签:StreamBuilder Widget package class dart import 工程化 data Flutter


本文章就不对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);
        },
      ),
    );
  }
}
磐石BedRock 发布了65 篇原创文章 · 获赞 19 · 访问量 4万+ 私信 关注

标签:StreamBuilder,Widget,package,class,dart,import,工程化,data,Flutter
来源: https://blog.csdn.net/qq_38774121/article/details/104405572

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有