Flutter的BloC架构简单实现

本文通过一个简单的计数器示例,深入浅出地讲解了Flutter中的Bloc架构。从准备步骤开始,逐步介绍了如何构建Counter相关类、放置监控、创建核心类进行数据管理,以及如何实现数据展示和广播功能。文章详细解析了CounterBloc、CounterInherited和StreamBuilder的作用及其实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

用简单的计数器来解释BloC架构,便于学习和使用

准备

Stream
InheritedWidget

步骤

步骤1建Counter相关类

抽离出无状态的CounterBody类和CounterActionButton类可单独放在一个dart文件

class CounterBody extends StatelessWidget      //抽离后放置一个ActionChip和Text
class CounterActionButton extends StatelessWidget  //抽离后放置一个FloatingActionButton
步骤2建放监控的类

建类CounterInherited,可以自动生成

class CounterInherited extends InheritedWidget {  //用于放置监控包裹在Scaffold上面
  CounterInherited({Key key, this.child, this.bloc}): super(key: key, child: child);
  final Widget child;      //用于可跟Scaffold ,有变动时后面的不会被重绘,节省资源
  final CounterBloc bloc;  //绑定数据管理源
  static CounterInherited of(BuildContext context) => //后面用于数据的展示和响应事件
      context.dependOnInheritedWidgetOfExactType<CounterInherited>();
  }
  @override
  bool updateShouldNotify(CounterInherited oldWidget) {
    return true
;  }}
步骤3建核心类

建类CounterBloc用于数据的管理,核心作用

class CounterBloc {         //核心,作用数据响应
  int _count = 0;            //存放数据
  final _counterActionController = StreamController<int>();  //动作流的控制器
  StreamSink<int> get counterActionSink => _counterActionController.sink; //动作流的水槽用于添加数据
  final _counterCountController =    //动作流监听到数据后让数字流发送数据,StreamBuild会自动更新
StreamController<int>.broadcast();   //数字流有广播功能,收到后都会自动更新
  Stream<int> get counterCountStream => _counterCountController.stream; //和StreamBuild的stream参数绑定
  CounterBloc() {
    _counterActionController.stream.listen(onActionData);  } //构造函数里启动监听,有数据后执行onActionData
  void onActionData(int data) {            //动作流有数据后执行该方法
    _count = data + _count;               //变量累加
    _counterCountController.add(_count);  }  //然后给数字流发送一个数据,让他的StreamBuild自动更新
  void dispose() {
    _counterActionController.close();       //释放资源
    _counterCountController.close();  }}
步骤4放置监控

用CounterInherited来包裹Scaffold

CounterInherited(              //通过CounterInherited.of(context).bloc能回访数据
      		bloc: CounterBloc(),        //数据绑定, 实例化CouterBloc        
      child: Scaffold(
        appBar: AppBar(
          title: Text("Bloc的演示"),        ),
        body: CounterBody(),
        floatingActionButton: CounterActionButton(),      ),    );
步骤5数据展示-按钮

定义类变量_counterBloc,用于临时存放通过CounterInherited.of获取CounterBloc
按钮上数据关联展示用_counterBloc来添加动作流数据

class CounterActionButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    CounterBloc _counterBloc = CounterInherited.of(context).bloc;   //获取CounterBloc
    return FloatingActionButton(
      child: Icon(Icons.add),
      onPressed: () {                            //动作流的监听器已经在构造函数里启动
        _counterBloc.counterActionSink.add(1);      },    );  }}  //listen监听到后onActionData响应
步骤6数据展示-标签和按钮

在类中新建成员_counterBloc通过CounterInherited.of(context).bloc获取CounterBloc

StreamBuilder(
            stream: _counterBloc.counterCountStream,  //绑定这个,用来监听到数字流后重绘
            initialData: 0,
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              return Container(
                child: ActionChip(
                    avatar: Icon(Icons.add),
                    label: Text('${snapshot.data}'),
                    onPressed: () {                     //和另一个按钮使用同一个,也给数据
                      _counterBloc.counterActionSink.add(1);    }),  );   },          ), //让动作流开始监听响应
步骤7数据展示-广播功能
StreamBuilder(
            stream: _counterBloc.counterCountStream,   //绑定数字流,监听到数据后重绘
            initialData: 0,
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              return Container(
                child: Text('利用广播功能接收数据:${snapshot.data}'),             );            },          ),
步骤8总体说明

类CounterBloc 数据中心,数据控制
_count 存放数据数字
_counterActionController 动作流控制器,他包含stream,sink,也能add数据
counterActionSink 动作控制的动作监听的水槽 _counterActionController.sink
_counterCountController 数字流控制器
countStream 数字控制的流 _counterController.stream,流上数字和_count对应
构造函数作用开始监听动作流 _counterActionController.stream.listen(onData)
有数据后onActionData(int data)方法,给存放数据的变量累加,以及同时给数字流add(累加后变量)
类CounterInherited 绑定功能
用于包裹Scaffold,赋值通过CounterInherited.of(context).bloc返回CounterBloc
其类成员bloc,用于启动关联实例CounterBloc,一切的开始
棋类成员child ,用来包裹Scaffold,这个后面的Widget数据变化时不会重绘
类StreamBuilder 绑定功能,响应功能
生成Widget并结合CounterInherited.of(context).bloc让数据更好展示

代码

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
  SystemUiOverlayStyle systemUiOverlayStyle =
      SystemUiOverlayStyle(statusBarColor: Colors.transparent);
  SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
}
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BlocScaffold (),
    );
  }
}
class BlocScaffold extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("在scaffold上一层");
    return CounterInherited(
      bloc: CounterBloc(), //数据绑定
      child: Scaffold(
        appBar: AppBar(
          title: Text("Bloc的演示"),
        ),
        body: CounterBody(),
        floatingActionButton: CounterActionButton(),
      ),
    );
  }
}

class CounterBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("body抽离后在scaffold下一层");
    CounterBloc _counterBloc = CounterInherited.of(context).bloc; //CounterBloc
    return Container(
      width: double.infinity,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          StreamBuilder(
            stream: _counterBloc.counterCountStream,
            initialData: 0,
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              return Container(
                child: Text('利用广播功能接收数据:${snapshot.data}'),
              );
            },
          ),
          SizedBox(height:10 ),
          StreamBuilder(
            stream: _counterBloc.counterCountStream,
            initialData: 0,
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              return Container(
                child: ActionChip(
                    avatar: Icon(Icons.add),
                    label: Text('${snapshot.data}'),
                    onPressed: () {
                      _counterBloc.counterActionSink.add(1);
                    }),
              );
            },
          ),
        ],
      ),
    );
  }
}

class CounterActionButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    CounterBloc _counterBloc = CounterInherited.of(context).bloc;
    return FloatingActionButton(
      child: Icon(Icons.add),
      onPressed: () {
        _counterBloc.counterActionSink.add(1);
      },
    );
  }
}

class CounterInherited extends InheritedWidget {
  CounterInherited({Key key, this.child, this.bloc})
      : super(key: key, child: child);

  final Widget child;
  final CounterBloc bloc;
  static CounterInherited of(BuildContext context) => //后面用于数据的展示和响应事件
      context.dependOnInheritedWidgetOfExactType<CounterInherited>();
  @override
  bool updateShouldNotify(CounterInherited oldWidget) {
    return true;
  }
}

class CounterBloc {
  int _count = 0;

  final _counterActionController = StreamController<int>.broadcast();
  StreamSink<int> get counterActionSink => _counterActionController.sink;

  final _counterCountController = StreamController<int>.broadcast();
  Stream<int> get counterCountStream => _counterCountController.stream;

  CounterBloc() {
    _counterActionController.stream.listen(onActionData);
  }
  void onActionData(int data) {
    _count = data + _count;
    _counterCountController.add(_count);
  }

  void dispose() {
    _counterActionController.close();
    _counterCountController.close();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值