Flutter中的BLoC,你所需要知道的一切

本文详细介绍了Flutter中的BLoC架构模式,阐述了其基于单一责任原则的工作原理,如何通过流管理和分离业务逻辑、数据与视图。文章探讨了BLoC的优点(代码重用、可测试性)和缺点(学习成本、增加代码量),并给出了使用BLoC的步骤和示例,以及高级功能如状态管理和复杂状态处理的示例应用。
摘要由CSDN通过智能技术生成

Flutter中的BLoC(Business Logic Component)是一种用于构建可重用的业务逻辑组件的架构模式。它基于单一责任原则,将业务逻辑从UI层分离出来,并通过流(Stream)将它们连接起来。下面是对BLoC的更详细的介绍:

概念:

BLoC是一种基于单一责任原则的架构模式,它将应用程序分为三个主要部分:视图(View)、业务逻辑(Business Logic)和数据(Data)。BLoC的主要思想是将业务逻辑与UI分离,并通过流将它们连接起来。

功能:

BLoC的主要功能是将业务逻辑与UI分离,从而使得应用程序更易于维护和扩展。它还允许开发人员将业务逻辑组件化,从而可以在不同的应用程序中重用。

原理:

BLoC基于流(Stream)的概念,使用RxDart库中的StreamController和Stream来实现。BLoC将UI层(如widget)中的用户操作通过事件(Event)发送给业务逻辑层,并根据这些事件处理数据并生成新的状态(State),再将新状态传递回UI层以更新视图。

优点:

1、代码重用性:BLoC可以将业务逻辑组件化,从而可以在不同的应用程序中重用。
2、分离关注点:BLoC使得业务逻辑与UI分离,使得应用程序更易于维护和扩展。
3、可测试性:BLoC的业务逻辑可以通过单元测试进行测试,从而提高代码的质量和可靠性。

缺点:

1、学习成本:学习BLoC需要一定的学习成本,因为它需要掌握一些新的概念和技术。
2、增加代码量:使用BLoC需要编写更多的代码,因为它需要将业务逻辑从UI层中分离出来。

使用方法:

1、安装RxDart库:BLoC使用RxDart库中的StreamController和Stream来实现。因此,需要安装RxDart库。
2、创建BLoC类:创建一个BLoC类来处理业务逻辑。BLoC类通常包含一个StreamController和一个Stream。
3、在UI层中使用BLoC:在UI层中使用BLoC,将用户操作转换为事件,并根据BLoC的状态来更新UI。

使用范例:

假设我们要开发一个计数器应用程序,可以使用BLoC来处理计数器的逻辑。下面是一个使用BLoC实现的简单计数器应用程序的代码:

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart;

class CounterBloc {
  int _counter = 0;
  final _counterController = BehaviorSubject<int>();

  Stream<int> get counterStream => _counterController.stream;

  void incrementCounter() {
    _counter++;
    _counterController.add(_counter);
  }

  void dispose() {
    _counterController.close();
  }
}

class CounterApp extends StatefulWidget {
  
  _CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
  final _bloc = CounterBloc();

  
  void dispose() {
    _bloc.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: StreamBuilder<int>(
          stream: _bloc.counterStream,
          initialData: 0,
          builder: (context, snapshot) {
            return Text('Count: ${snapshot.data}');
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _bloc.incrementCounter();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个示例中,我们首先创建了一个CounterBloc类来处理计数器的逻辑。CounterBloc类包含一个计数器变量_counter和一个StreamController _counterController,用于向UI层发送计数器变化的事件。

我们使用getter方法counterStream将CounterBloc类中的_streamController暴露为流Stream。incrementCounter方法用于增加计数器变量_counter的值,并通过_counterController向UI层发送新的计数器值。最后,我们通过dispose方法来关闭CounterBloc类中的流StreamController。

在UI层中,我们创建一个CounterApp小部件,它包含一个StreamBuilder小部件,用于在UI层中显示计数器的值。我们在CounterApp的状态类_CounterAppState中创建CounterBloc的实例_bloc,并在小部件的dispose方法中调用bloc.dispose()来关闭CounterBloc中的StreamController。

我们将_bloc.counterStream流传递给StreamBuilder,这样我们就可以监听计数器变化的事件。StreamBuilder会自动重建并更新UI层,以反映新的计数器值。在floatingActionButton中,我们使用_bloc.incrementCounter()方法将新的计数器值发送到CounterBloc类中。

使用过程注意点:

1、BLoC的使用需要掌握RxDart库中的StreamController和Stream概念,并理解BLoC的核心思想。
2、在使用BLoC时,应该尽量将业务逻辑从UI层分离出来,以使代码更易于维护和扩展。
3、在使用BLoC时,应该注意处理好流的生命周期,以防止内存泄漏问题的出现。要及时调用流的dispose方法来释放资源。
4、使用BLoC可以使应用程序更易于测试,因此建议使用单元测试来确保代码的质量和可靠性。

优点:

1、BLoC可以将业务逻辑和UI层分离,使代码更易于维护和扩展。
2、BLoC使用流来处理数据,可以实现响应式编程,让UI层更加流畅和灵活。
3、BLoC可以轻松地进行单元测试,因为业务逻辑和UI层分离,可以独立地测试业务逻辑的正确性。
4、BLoC可以在多个屏幕之间共享数据和状态,使得应用程序的代码更加清晰和模块化。

缺点:

1、使用BLoC需要掌握一定的Rx编程知识,学习成本较高。
2、BLoC中的代码比较复杂,容易出现嵌套回调地狱的情况,需要合理的代码组织和封装。
3、BLoC的性能可能会受到影响,特别是在处理大量数据时。

使用方法:

1、引入rxdart库:在pubspec.yaml文件中添加rxdart依赖。

dependencies: 
  rxdart: ^0.27.2

2、创建BLoC类:BLoC类应该包含数据处理逻辑和状态管理的方法,以及StreamController来向UI层发送数据更新事件。BLoC类应该根据业务逻辑来定义,可以参考上面的计数器示例。

3、在UI层使用StreamBuilder:使用StreamBuilder来监听BLoC类中的流,以反映数据的变化。StreamBuilder会自动重建并更新UI层。

4、在UI层中使用BLoC:在UI层中实例化BLoC类,并在需要的地方调用BLoC中的方法来处理业务逻辑和状态管理。

使用过程注意点:

1、BLoC的使用需要掌握RxDart库中的StreamController和Stream概念,并理解BLoC的核心思想。
2、在使用BLoC时,应该尽量将业务逻辑从UI层分离出来,以使代码更易于维护和扩展。
3、在使用BLoC时,应该注意处理好流的生命周期,以防止内存泄漏问题的出现。要及时调用流的dispose方法来释放资源。
4、使用BLoC可以使应用程序更易于测试,因此建议使用单元测试来确保代码的质量和可靠性。
5、在使用BLoC时,需要注意在BLoC类中维护数据的一致性和正确性,特别是在多个UI层中共享同一个BLoC对象时,要确保数据的正确性。
6、在BLoC类中处理异步操作时,应该使用异步函数和异步等待来处理异步任务,以避免造成UI线程的阻塞和卡顿现象。
7、在使用BLoC时,可以使用第三方库如flutter_bloc来简化BLoC的使用和管理,该库提供了许多便捷的工具和API来处理常见的业务逻辑和状态管理。
8、在使用BLoC时,应该遵循单一职责原则和依赖倒置原则,尽可能地将业务逻辑和状态管理从UI层分离出来,并使用依赖注入来实现解耦。
9、在使用BLoC时,可以通过使用流的操作符来处理数据,如map、where、fold等操作符,以实现更加复杂的数据转换和处理逻辑。
10、在使用BLoC时,需要注意错误处理和异常捕获,特别是在处理异步操作时,需要使用try-catch语句来捕获异步任务中的异常,并向上层传递错误信息。

另外:

1、BLoC是一种可复用的模式,可以在整个应用程序中使用。它是一种非常灵活的模式,可以根据不同的需求进行定制和扩展。
2、在使用BLoC时,可以通过组合和嵌套的方式来构建复杂的业务逻辑和状态管理。例如,可以将多个BLoC对象组合在一起,以处理更加复杂的数据流和业务逻辑。
3、BLoC可以与其他Flutter框架和库一起使用,如Provider、GetIt、MobX等。这些框架和库可以进一步简化BLoC的使用和管理,以提高代码的可读性和可维护性。
4、BLoC可以通过使用Code Generator来生成BLoC类的模板代码,以提高开发效率和代码质量。例如,可以使用flutter_bloc库提供的bloc_template命令来生成BLoC类的模板代码。
5、在使用BLoC时,可以通过使用Flutter DevTools来调试和分析数据流,以实现更加高效的调试和优化。

flutter_bloc插件 :https://pub.dev/packages/bloc

flutter_bloc是一个Flutter状态管理库,它的主要功能是帮助开发者更好地组织和管理Flutter应用程序中的状态,并且将UI和业务逻辑分离,使得代码更加清晰、易于维护。

Flutter自带的Bloc库是Google官方提供的,而flutter_bloc是由第三方开发者创建和维护的,它们有一些联系和区别。

联系:

1、基本概念类似:

Flutter自带的Bloc库和flutter_bloc库的基本概念是类似的,包括Bloc、Event和State等。

2、都可以实现状态管理

Flutter自带的Bloc库和flutter_bloc库都可以实现状态管理,通过将状态存储在Bloc中,并使用Stream和yield关键字将状态输出到UI层。

3、都适用于Flutter应用程序

Flutter自带的Bloc库和flutter_bloc库都是为Flutter应用程序而设计的,可以在Flutter应用程序中使用。

区别:

1、使用方式不同

Flutter自带的Bloc库使用的是原生的Stream API和语言特性,而flutter_bloc库使用了更高级的Dart语言特性和第三方库,例如equatable和hydrated_bloc。

2、功能和特性不同

Flutter自带的Bloc库提供了一些基本的功能和特性,例如处理异步事件和状态管理等。而flutter_bloc库提供了更多的功能和特性,例如自动化测试、依赖注入、高级状态管理等。

功能

1、提供了一个Bloc类和一个Cubit类,用于实现业务逻辑和状态管理。Bloc类是一个抽象类,它提供了基本的状态管理功能和事件处理方法,而Cubit类则是Bloc类的一个子类,它提供了更加简单的API和更少的模板代码。
2、提供了一个BlocBuilder小部件和一个BlocListener小部件,用于在UI层中监听BLoC的状态变化并更新UI。BlocBuilder小部件可以根据BLoC的状态自动构建UI,并在状态变化时自动更新UI,而BlocListener小部件则可以监听BLoC的状态变化并执行一些副作用操作。
3、提供了一个MultiBlocProvider小部件和一个BlocProvider小部件,用于在应用程序中管理多个BLoC对象和依赖注入。MultiBlocProvider小部件可以同时管理多个BLoC对象,而BlocProvider小部件则可以为子树提供一个BLoC对象。

插件使用举例

首先,需要在pubspec.yaml文件中添加flutter_bloc依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^7.3.1


然后,创建一个CounterBloc类来实现计数器的业务逻辑和状态管理:

import 'package:bloc/bloc.dart';

class CounterBloc extends Bloc<int, int> {
  CounterBloc() : super(0);

  
  Stream<int> mapEventToState(int event) async* {
    yield state + event;
  }
}


在这个例子中,CounterBloc类继承自Bloc类,并定义了一个泛型类型参数int,表示BLoC的状态类型和事件类型都是整数。CounterBloc类的构造函数中,使用super调用父类的构造函数,将初始状态设置为0。

然后,重写mapEventToState方法,用于处理事件和更新状态。在这个例子中,事件是一个整数,表示计数器需要增加的值,而状态是一个整数,表示计数器的当前值。在mapEventToState方法中,将事件与当前状态相加,并通过yield关键字将新的状态作为流的输出。

接下来,使用BlocProvider小部件将CounterBloc对象提供给UI层:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (BuildContext context) => CounterBloc(),
      child: MaterialApp(
        title: 'Flutter Bloc Example',
        home: MyHomePage(),
      ),
    );
  }
}


在这个例子中,使用BlocProvider小部件将CounterBloc对象提供给UI层。在BlocProvider的create回调函数中,创建一个CounterBloc对象,并将其提供给BlocProvider。然后,在MyHomePage小部件中,使用BlocBuilder小部件和BlocProvider.of方法来监听CounterBloc的状态变化并更新UI:

class MyHomePage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Bloc Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            BlocBuilder<CounterBloc, int>(
              builder: (context, state) {
                return Text(
                  '$state',
                  style: TextStyle(fontSize: 24.0),
                );
              },
            ),
            SizedBox(height: 20.0),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                FloatingActionButton(
                  onPressed: () {
                    BlocProvider.of<CounterBloc>(context).add(1);
                  },
                  child: Icon(Icons.add),
                ),
                SizedBox(width: 20.0),
                FloatingActionButton(
                  onPressed: () {
                    BlocProvider.of<CounterBloc>(context).add(-1);
                  },
                  child: Icon(Icons.remove),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}


在上面的代码中,BlocBuilder小部件监听CounterBloc的状态变化,并在状态变化时自动构建UI,其中context.read()可以用来获取CounterBloc实例,并通过add方法向其发送事件。

这样,就实现了一个简单的计数器应用程序,通过使用flutter_bloc插件的BlocProvider和BlocBuilder小部件来实现BLoC模式的业务逻辑和状态管理。

高级功能

除了上面提到的基本使用方法外,flutter_bloc插件还提供了一些高级功能,下面简单介绍一下:

多Bloc的使用

有时候,在应用程序中需要使用多个Bloc来处理不同的业务逻辑,此时可以使用MultiBlocProvider小部件来提供多个Bloc实例,例如:

MultiBlocProvider(
  providers: [
    BlocProvider<CounterBloc>(
      create: (context) => CounterBloc(),
    ),
    BlocProvider<TimerBloc>(
      create: (context) => TimerBloc(),
    ),
  ],
  child: MyApp(),
)


高级状态管理

在一些复杂的应用程序中,状态可能会非常复杂,此时可以使用flutter_bloc插件提供的State类和Equatable库来实现高级状态管理。

例如,定义一个复杂的状态类:

class MyState extends Equatable {
  final int count;
  final String text;

  MyState({this.count, this.text});

  MyState copyWith({int count, String text}) {
    return MyState(
      count: count ?? this.count,
      text: text ?? this.text,
    );
  }

  
  List<Object> get props => [count, text];
}


上面的代码中,MyState类继承自Equatable类,通过重写props属性来定义对象相等的比较方法。

然后,在Bloc中使用MyState类作为状态:

class MyBloc extends Bloc<MyEvent, MyState> {
  MyBloc() : super(MyState(count: 0, text: ''));

  
  Stream<MyState> mapEventToState(MyEvent event) async* {
    if (event is IncrementEvent) {
      yield state.copyWith(count: state.count + 1);
    } else if (event is DecrementEvent) {
      yield state.copyWith(count: state.count - 1);
    } else if (event is SetTextEvent) {
      yield state.copyWith(text: event.text);
    }
  }
}


在上面的代码中,MyBloc使用MyState作为状态,并通过copyWith方法来生成新的状态对象。

最后,在UI层中使用BlocBuilder小部件来监听MyBloc的状态变化,并更新UI:

BlocBuilder<MyBloc, MyState>(
  builder: (context, state) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          'Count: ${state.count}',
          style: TextStyle(fontSize: 24),
        ),
        SizedBox(height: 24),
        Text(
          'Text: ${state.text}',
          style: TextStyle(fontSize: 24),
        ),
      ],
    );
  },
)


在上面的代码中,使用BlocBuilder小部件来监听MyBloc的状态变化,并在状态变化时自动构建UI。

通过使用Equatable库和State类,可以更好地管理复杂的状态,并提高应用程序的可维护性。

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
图片

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值