02 Flutter BBS 优雅的使用bloC项目解偶(不仅仅是UI)

用户界面使用bloc解偶

《02 Flutter BBS 优雅的使用bloC项目解偶(不仅仅是UI)》 用户页面示例

简而言之,业务逻辑需要:
1.转移到一个或几个BLoC,
2.尽可能从表示层中删除。换句话说,UI组件应该只关心UI本身而不关心业务,
3.依赖Streams 使用输入流(Sink)和输出流(Stream),
4.保持平台独立,
5.保持环境独立。
事实上,BLoC模式最初被设想为允许独立于平台重用相同的代码:Web应用程序,移动应用程序,后端。

《02 Flutter BBS 优雅的使用bloC项目解偶(不仅仅是UI)》 block流程图

  • 组件通过Sink向BLoC 发送事件,
  • BLoC通过流通知组件,
  • 由BLoC实现的业务逻辑不是他们关注的问题。

从这个声明中,我们可以直接看到一个巨大的好处。

业务逻辑与UI的分离:

  • 我们可以随时更改业务逻辑,对应用程序的影响最小,
  • 我们可能会更改UI而不会对业务逻辑产生任何影响,
  • 现在,测试业务逻辑变得更加容易。

通用BlocProvider



import 'package:flutter/material.dart';

abstract class BlocBase {
  void dispose();
}

class BlocProvider<T extends BlocBase> extends StatefulWidget {
  BlocProvider({
    Key key,
    @required this.child,
    @required this.bloc,
  }): super(key: key);

  final T bloc;
  final Widget child;

  @override
  _BlocProviderState<T> createState() => _BlocProviderState<T>();

  static T of<T extends BlocBase>(BuildContext context){
    final type = _typeOf<BlocProvider<T>>();
    BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
    return provider.bloc;
  }

  static Type _typeOf<T>() => T;
}

class _BlocProviderState<T> extends State<BlocProvider<BlocBase>>{
  @override
  void dispose(){
    widget.bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context){
    return widget.child;
  }
}

UserBloc

import 'dart:async';

import 'package:flutter_bbs_client/model/userEntity.dart';
import 'package:flutter_bbs_client/service/api.dart';
import 'package:flutter_bbs_client/widgets/bloc_provider.dart';

class UserBloc extends BlocBase{

  UserEntity _userEntity;

  StreamController<UserEntity> _userController = StreamController<UserEntity>.broadcast();

  Sink<UserEntity> get _inUser => _userController.sink;
  Stream<UserEntity> get outUser => _userController.stream;

  StreamController<String> _refreshController = StreamController<String>.broadcast();
  Sink<String> get refreshUser => _refreshController.sink;

  UserBloc(){
    getUserInfo().then((userEntity){
      _userEntity= userEntity;
      _inUser.add(userEntity);
    });

    _refreshController.stream.listen((name){
      getUserInfo().then((userEntity){
        _userEntity= userEntity;
        _userEntity.attention = _userEntity.attention+1;
        _inUser.add(userEntity);
      });
    });

  }


  @override
  void dispose() {
    _userController.close();
    _refreshController.close();
  }

}

用户模型

class UserEntity {
    /// 粉丝
    double fan;
    /// 积分
    double integral;
    /// 名称
    String name;
    /// 关注
    double attention;
    /// id
    double id;
    /// 文章
    double article;

    String imageUrl;

    UserEntity({this.fan, this.integral, this.name, this.attention, this.id, this.article, this.imageUrl});

    UserEntity.empty(){
        this.fan = 0;
        this.integral = 0;
        this.name = '';
        this.attention = 0;
        this.id = 0;
        this.article = 0;
        this.imageUrl = 'images/default_avatar.jpg';
    }

    UserEntity.fromJson(Map<String, dynamic> json) {
        fan = json['fan'];
        integral = json['integral'];
        name = json['name'];
        attention = json['attention'];
        id = json['id'];
        article = json['article'];
        imageUrl = json['imageUrl'];
    }

    Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        data['fan'] = this.fan;
        data['integral'] = this.integral;
        data['name'] = this.name;
        data['attention'] = this.attention;
        data['id'] = this.id;
        data['article'] = this.article;
        data['imageUrl'] = this.imageUrl;
        return data;
    }
}

个人中心页面

import 'package:flutter/material.dart';
import 'package:flutter_bbs_client/bloc/user_bloc.dart';
import 'package:flutter_bbs_client/pages/person_bloc_page.dart';
import 'package:flutter_bbs_client/widgets/bloc_provider.dart';
import 'package:flutter/cupertino.dart';

/// 个人中心页面
class PersonPage extends StatefulWidget {
  @override
  PersonPageState createState() => new PersonPageState();
}

class PersonPageState extends State<PersonPage> {


  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      backgroundColor: Colors.white10,
      body: BlocProvider<UserBloc>(
        child:  PersonBlocPage(),
        bloc: UserBloc(),
      )
    );
  }



  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }

  @override
  void didUpdateWidget(PersonPage oldWidget) {
    // TODO: implement didUpdateWidget
    super.didUpdateWidget(oldWidget);
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }
}

个人中心 PersonBlocPage

import 'package:flutter/material.dart';
import 'package:flutter_bbs_client/bloc/user_bloc.dart';
import 'package:flutter_bbs_client/model/userEntity.dart';
import 'package:flutter_bbs_client/pages/home.dart';
import 'package:flutter_bbs_client/widgets/bloc_provider.dart';
import 'package:flutter_bbs_client/widgets/divider.dart';
import 'package:flutter_bbs_client/widgets/group.dart';
import 'package:flutter_bbs_client/widgets/item.dart';

class PersonBlocPage extends StatefulWidget {
  @override
  PersonBlocPageState createState() => new PersonBlocPageState();
}

class PersonBlocPageState extends State<PersonBlocPage> {

  Future<Null> _refresh(UserBloc userBloc) async {
    userBloc.refreshUser.add('refresh');
  }

  @override
  Widget build(BuildContext context) {
    final UserBloc userBloc = BlocProvider.of<UserBloc>(context);
    return RefreshIndicator(
        onRefresh: () =>_refresh(userBloc),
        child: StreamBuilder<UserEntity>(
            stream: userBloc.outUser,
            builder:
                (BuildContext context, AsyncSnapshot<UserEntity> snapshot) {
              if(!snapshot.hasData) {
                return Center(
                  child: Container(
                    child: CircularProgressIndicator(),
                  ),
                );
              }
              return ListView(
                children: [
                  _head(snapshot.data),
                  Center(child: _card(context)),
                  Center(
                    child: Padding(
                      padding: const EdgeInsets.only(left: 15, right: 15.0),
                      child: SettingsGroup(<Widget>[
                        SettingsItem(
                          label: 'FS会员',
                          iconAssetLabel: 'huiyuan',
                          type: SettingsItemType.modal,
                          hasDetails: true,
                          onPress: () => Navigator.push(
                                context,
                                MaterialPageRoute(
                                    builder: (context) => HomePage()),
                              ),
                        ),
                        SettingsItem(
                          label: 'FS活动',
                          iconAssetLabel: 'huodong',
                          type: SettingsItemType.modal,
                          hasDetails: true,
                        ),
                        SettingsItem(
                          label: '浏览历史',
                          iconAssetLabel: 'liulanlishi',
                          type: SettingsItemType.modal,
                          hasDetails: true,
                        ),
                        SettingsItem(
                          label: '我的钱包',
                          iconAssetLabel: 'qianbao',
                          type: SettingsItemType.modal,
                          hasDetails: true,
                        ),
                      ]),
                    ),
                  )
                ],
              );
            }));
  }


  Widget _card(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
      child: Card(
        color: Colors.white,
        elevation: 0.5,
        child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text('FS钻石:88'),
                  ],
                ),
                SizedBox(
                  height: 5.0,
                ),
                CustomDivider(
                  height: 1.0,
                ),
                SizedBox(
                  height: 15.0,
                ),
                Row(
                  children: [
                    _cardItem('article', '我对文章', '1篇私密', context),
                    _cardItem('tushu', '我的书架', '含已购', context),
                    _cardItem('shoucang', '我的收藏', '', context),
                    _cardItem('jianglibang', '奖励任务', '领FB钻', context),
                  ],
                )
              ],
            )),
      ),
    );
  }

  Widget _cardItem(
      String img, String title, String subTitle, BuildContext context) {
    return Expanded(
      flex: 1,
      child: Center(
        child: Column(
          children: [
            Image.asset(
              'images/$img.png',
              width: 35.0,
            ),
            SizedBox(
              height: 5.0,
            ),
            Text(
              '$title',
              style: TextStyle(fontSize: 15.0),
            ),
            SizedBox(
              height: 3.0,
            ),
            Text(
              '$subTitle',
              style: TextStyle(fontSize: 10.0),
            )
          ],
        ),
      ),
    );
  }

  Widget _head(UserEntity uerEntity) {
    return Padding(
      padding: const EdgeInsets.only(top: 15.0),
      child: Row(
        children: [
          Padding(
            padding: const EdgeInsets.only(left: 15.0, right: 15.0),
            child: Container(
              width: 60,
              height: 60,
              child: CircleAvatar(
                backgroundImage: ExactAssetImage('${uerEntity.imageUrl}'),
              ),
            ),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                '${uerEntity.name}',
                style: TextStyle(fontSize: 20.0),
              ),
              Row(
                children: [
                  _headFooter(uerEntity.attention, '关注'),
                  SizedBox(
                    width: 30.0,
                  ),
                  _headFooter(uerEntity.fan, '粉丝'),
                  SizedBox(
                    width: 30.0,
                  ),
                  _headFooter(uerEntity.integral, '积分'),
                ],
              )
            ],
          )
        ],
      ),
    );
  }

  Widget _headFooter(num, title) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('$num'),
        Text('$title'),
      ],
    );
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }

  @override
  void didUpdateWidget(PersonBlocPage oldWidget) {
    // TODO: implement didUpdateWidget
    super.didUpdateWidget(oldWidget);
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }
}

以上代码可供参考 从项目中提取 并不全 希望可以帮到各位道友,你也可以加入qq群向我提问,若帮到你希望你能给予支持或评论 我尽快回复你的问题

加入QQ群950676175
《02 Flutter BBS 优雅的使用bloC项目解偶(不仅仅是UI)》 FlutterBBS群二维码.png

    原文作者:LOVE信
    原文地址: https://www.jianshu.com/p/c7c007f367c9
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞