阅读 128

Flutter中使用Bloc做状态管理实践

flutter中滥用stateFul组件将会导致组件不停的发生重绘,浪费性能,在更新一个页面的某一个区域的时候我们可以做一个局部的更新即可,为了达到这个目的,我们将要使用stateless组件,而更新stateless组件或许我们就将使用到状态管理。
flutter的状态管理方式有很多,为什么我这里选择Bloc? Bloc在我看来使用的思想类似MVVM的思想方式,数据视图解耦,通过事件驱动数据,在flutter中使用的streamWidget来进行视图的更新变化。 Bloc的官图:

image.png

话不多说,撸起袖子实践一下:

这里我使用的IDE是Android studio,第一步可以先安装Bloc的插件: 打开 Android studio的preferences,然后选中plugins的Marketplace,输入Bloc,下载,安装。

image.png 装好插件后,我们可以新建一个cubit的类:
我们所有关于Bloc的data层和事件逻辑都将在这里完成。 image.png 这里我直接上一个我在业务中写的一个页面和状态,页面的结构如下图所示:

image.png 这里我取connectUs这个页面做演示:

cubit的代码如下:

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:huo_shao_gou/api/content.dart';
import 'package:huo_shao_gou/models/respContentList.dart';

part 'connect_us_state.dart';

class ConnectUsCubit extends Cubit<PageState> {
  // 给与PageState初始化状态:loading
  ConnectUsCubit() : super(PageState.loading());

  // 请求页面的逻辑
  Future initPage () async {

    final ResponseContentList _res =  await getContent(
      'contact_us',
      '100',
      '1'
    );

    var _temp = {};
    _res.data!.list!.forEach((e) {
      if (e.title == '微 博') {
        _temp['weibo'] = e.summary;
      } else if (e.title == '官网') {
        _temp['web'] = e.summary;
      } else if (e.title == '联系电话') {
        _temp['tel'] = e.summary;
      } else if (e.title == '开放时间') {
        _temp['openTime'] = e.summary;
      }
    });
    
    // 触发事件响应,将数据传回视图层
   emit(PageState.success(_temp['tel'], _temp['web'], _temp['weibo'], _temp['openTime']));
  }
}
复制代码

state的部分:

part of 'connect_us_cubit.dart';

// equatable的作用是对比检查,只更新改变的部分,这里使用一个叫ConnectUsState的类来继承它的抽象类
abstract class ConnectUsState extends Equatable {
  const ConnectUsState();
}

// 枚举了pageStatus的状态:loading、success、failure
enum PageStatus { loading, success, failure }

class PageState extends ConnectUsState {
  // 这个私有类用来给state赋值
  PageState._({
    this.tel,
    this.web,
    this.weibo,
    this.openTime,
    this.status
  });
  
  // 给pageState增加一个loading状态:
  PageState.loading() : this._(status: PageStatus.loading);
  
  // 给pageState增加一个success状态并赋值state:
  PageState.success(String tel, String web, String weibo, String openTime )
    : this._(tel: tel, web: web, weibo: weibo, openTime: openTime, status: PageStatus.success);

  // state的数据
  final String ? tel;
  final String ? web;
  final String ? weibo;
  final String ? openTime;
  final status;

  // 重写get方法
  @override
  List<Object?> get props => [tel, web, weibo, openTime,status];
}
复制代码

视图部分(index.dart):

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:huo_shao_gou/pages/connectUs/connect_us_cubit.dart';

import 'connect_us_cubit.dart';

class ConnectUs extends StatelessWidget {
  const ConnectUs({Key ? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      // 初始化页面状态,调用initPage方法(即cubit中的方法)
      create: (BuildContext context) => ConnectUsCubit()..initPage(),
      child: BlocBuilder<ConnectUsCubit, PageState>(
        builder: (context, state) {
          // 不同的状态,渲染不同的页面
          switch (state.status) {
            case PageStatus.loading:
              return Center(
                child: Text('读取中...')
              );
            case PageStatus.success:
              return _page(state);
            default:
              return Text('出错');
          }
        }
      )
    );
  }

  Widget _page (state) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 20.w),
      child: Column(
        children: [
          Container(
            margin: EdgeInsets.only(top: 15.h),
            child: Row(
              children: [
                Expanded(
                  flex: 2,
                  child: Row(
                    children: [
                      Container(width: 40.w),
                      Image.asset('assets/images/connectUs/tel.png', height: 15.sp, width: 15.sp),
                      Container(width: 10.w),
                      Text('电话', style: TextStyle(
                        fontWeight: FontWeight.bold
                      ))
                    ],
                  )
                ),
                Expanded(
                  flex: 3,
                  child: Text(state.tel == null ? '' : state.tel!)
                )
              ],
            )
          ),
          Container(
            margin: EdgeInsets.only(top: 15.h),
            child: Row(
              children: [
                Expanded(
                  flex: 2,
                  child: Row(
                    children: [
                      Container(width: 40.w),
                      Image.asset('assets/images/connectUs/web.png', height: 15.sp, width: 15.sp),
                      Container(width: 10.w),
                      Text('官网', style: TextStyle(
                        fontWeight: FontWeight.bold
                      ))
                    ],
                  )
                ),
                Expanded(
                  flex: 3,
                  child: Text(state.web == null ? '' : state.web!)
                )
              ],
            )
          ),
          Container(
            margin: EdgeInsets.only(top: 15.h),
            child: Row(
              children: [
                Expanded(
                  flex: 2,
                  child: Row(
                    children: [
                      Container(width: 40.w),
                      Image.asset('assets/images/connectUs/weibo.png', height: 15.sp, width: 15.sp),
                      Container(width: 10.w),
                      Text('微博', style: TextStyle(
                        fontWeight: FontWeight.bold
                      ))
                    ],
                  )
                ),
                Expanded(
                  flex: 3,
                  child: Text(state.weibo == null ? '' : state.weibo!)
                )
              ],
            )
          ),
          Container(height: 20.h),
          Row(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              Stack(
                children: [
                  Positioned(
                    child: Container(
                      decoration: BoxDecoration(
                        gradient: LinearGradient(
                          colors: [Color(0xFFdf5413), Colors.white],
                          begin: Alignment.topLeft,
                          end: Alignment.bottomRight
                        ),
                      ),
                      height: 20.h,
                      width: 20.w
                    ),
                    left: -0.w,
                    top: -4.h
                  ),
                  Text('开放时间', style: TextStyle(
                    fontSize: 20.sp,
                    fontWeight: FontWeight.bold
                  )),
                ],
              )
            ],
          ),
          Container(height: 40.h),
          Center(
            child: Text(state.openTime == null ? '' : state.openTime!, style: TextStyle(
              fontSize: 18.sp,
              fontWeight: FontWeight.bold
            )),
          )
        ],
      )
    );
  }
}
复制代码
文章分类
前端
文章标签