元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
Flutter基础
环境搭建与第一个应用
Dart语言快速入门
Flutter项目结构解析
▶
Widgets与布局
常用Widgets介绍
布局Widgets详解
自定义Widget创建
▶
状态管理
StatefulWidget与状态管理基础
Provider状态管理实战
BLoC模式入门
▶
导航与路由
页面导航基础
命名路由与参数传递
底部导航栏实现
▶
网络与数据存储
HTTP请求与Dio库使用
本地存储(SharedPreferences/SQLite)
Firebase集成指南
▶
打包与发布
Android应用打包
iOS应用打包
应用发布到商店指南
发布时间:
2025-03-22 22:35
↑
☰
# Flutter BLoC模式入门 ## 什么是BLoC模式? BLoC(Business Logic Component)是Flutter中一种流行的状态管理模式,它将应用程序分为三个核心层: - 数据层(Data Layer):负责数据获取和存储 - 业务逻辑层(Business Logic Layer):处理数据转换和业务规则 - 展示层(Presentation Layer):负责UI展示 ## BLoC的核心概念 ### 1. Stream和Sink BLoC模式基于Dart的Stream,主要包含两个核心概念: - Stream:数据流出的通道 - Sink:数据流入的通道 ```dart class CounterBloc { // 创建一个StreamController来管理计数器的值 final _counterController = StreamController<int>(); // 对外暴露Stream,用于监听数据 Stream<int> get counter => _counterController.stream; // 对外暴露Sink,用于接收事件 Sink<int> get counterSink => _counterController.sink; // 在不需要时关闭StreamController void dispose() { _counterController.close(); } } ``` ### 2. Event和State BLoC模式中的数据流转遵循:Event → BLoC → State 的模式: ```dart // 定义事件 abstract class CounterEvent {} class IncrementEvent extends CounterEvent {} class DecrementEvent extends CounterEvent {} // 定义状态 class CounterState { final int count; const CounterState(this.count); } // 完整的BLoC实现 class CounterBloc { final _stateController = StreamController<CounterState>(); final _eventController = StreamController<CounterEvent>(); int _count = 0; CounterBloc() { // 监听事件并处理 _eventController.stream.listen(_mapEventToState); } Stream<CounterState> get state => _stateController.stream; Sink<CounterEvent> get event => _eventController.sink; void _mapEventToState(CounterEvent event) { if (event is IncrementEvent) { _count++; } else if (event is DecrementEvent) { _count--; } _stateController.add(CounterState(_count)); } void dispose() { _stateController.close(); _eventController.close(); } } ``` ## 使用flutter_bloc包 ### 1. 添加依赖 ```yaml dependencies: flutter_bloc: ^8.1.3 ``` ### 2. 创建BLoC ```dart import 'package:flutter_bloc/flutter_bloc.dart'; // 事件 abstract class CounterEvent {} class IncrementPressed extends CounterEvent {} class DecrementPressed extends CounterEvent {} // BLoC class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0) { on<IncrementPressed>((event, emit) => emit(state + 1)); on<DecrementPressed>((event, emit) => emit(state - 1)); } } ``` ### 3. 提供BLoC ```dart void main() { runApp( BlocProvider( create: (context) => CounterBloc(), child: MyApp(), ), ); } ``` ### 4. 使用BLoC ```dart class CounterPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Counter')), body: Center( child: BlocBuilder<CounterBloc, int>( builder: (context, count) { return Text( '$count', style: TextStyle(fontSize: 24), ); }, ), ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ FloatingActionButton( child: Icon(Icons.add), onPressed: () => context .read<CounterBloc>() .add(IncrementPressed()), ), SizedBox(height: 8), FloatingActionButton( child: Icon(Icons.remove), onPressed: () => context .read<CounterBloc>() .add(DecrementPressed()), ), ], ), ); } } ``` ## 实战示例:待办事项应用 ### 1. 定义模型 ```dart class Todo { final String id; final String title; final bool completed; Todo({ required this.id, required this.title, this.completed = false, }); Todo copyWith({String? title, bool? completed}) { return Todo( id: id, title: title ?? this.title, completed: completed ?? this.completed, ); } } ``` ### 2. 定义事件和状态 ```dart // 事件 abstract class TodoEvent {} class AddTodo extends TodoEvent { final String title; AddTodo(this.title); } class ToggleTodo extends TodoEvent { final String id; ToggleTodo(this.id); } class DeleteTodo extends TodoEvent { final String id; DeleteTodo(this.id); } // 状态 class TodoState { final List<Todo> todos; TodoState(this.todos); } ``` ### 3. 实现BLoC ```dart class TodoBloc extends Bloc<TodoEvent, TodoState> { TodoBloc() : super(TodoState([])) { on<AddTodo>(_onAddTodo); on<ToggleTodo>(_onToggleTodo); on<DeleteTodo>(_onDeleteTodo); } void _onAddTodo(AddTodo event, Emitter<TodoState> emit) { final todo = Todo( id: DateTime.now().toString(), title: event.title, ); emit(TodoState([...state.todos, todo])); } void _onToggleTodo(ToggleTodo event, Emitter<TodoState> emit) { final todos = state.todos.map((todo) { if (todo.id == event.id) { return todo.copyWith(completed: !todo.completed); } return todo; }).toList(); emit(TodoState(todos)); } void _onDeleteTodo(DeleteTodo event, Emitter<TodoState> emit) { final todos = state.todos .where((todo) => todo.id != event.id) .toList(); emit(TodoState(todos)); } } ``` ### 4. 创建UI ```dart class TodoApp extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( create: (context) => TodoBloc(), child: MaterialApp( title: '待办事项', home: TodoPage(), ), ); } } class TodoPage extends StatelessWidget { final _controller = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('待办事项')), body: Column( children: [ Padding( padding: EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: TextField( controller: _controller, decoration: InputDecoration( hintText: '添加新的待办事项', ), ), ), IconButton( icon: Icon(Icons.add), onPressed: () { if (_controller.text.isNotEmpty) { context .read<TodoBloc>() .add(AddTodo(_controller.text)); _controller.clear(); } }, ), ], ), ), Expanded( child: BlocBuilder<TodoBloc, TodoState>( builder: (context, state) { return ListView.builder( itemCount: state.todos.length, itemBuilder: (context, index) { final todo = state.todos[index]; return ListTile( leading: Checkbox( value: todo.completed, onChanged: (_) { context .read<TodoBloc>() .add(ToggleTodo(todo.id)); }, ), title: Text( todo.title, style: TextStyle( decoration: todo.completed ? TextDecoration.lineThrough : null, ), ), trailing: IconButton( icon: Icon(Icons.delete), onPressed: () { context .read<TodoBloc>() .add(DeleteTodo(todo.id)); }, ), ); }, ); }, ), ), ], ), ); } } ``` ## 最佳实践 1. **单一职责原则**:每个BLoC只负责一个功能模块的状态管理 2. **依赖注入**:使用BlocProvider在widget树中提供BLoC实例 3. **状态不可变性**:确保状态对象是不可变的,使用copyWith方法创建新状态 4. **事件处理**:将复杂的业务逻辑封装在BLoC中,保持UI层简洁 5. **错误处理**:使用try-catch处理异常,并通过状态通知UI层 ```dart class DataState { final List<Item> items; final String? error; final bool isLoading; DataState({ required this.items, this.error, this.isLoading = false, }); } class DataBloc extends Bloc<DataEvent, DataState> { DataBloc() : super(DataState(items: [])) { on<FetchData>((event, emit) async { emit(DataState(items: [], isLoading: true)); try { final items = await repository.fetchItems(); emit(DataState(items: items)); } catch (e) { emit(DataState(items: [], error: e.toString())); } }); } } ``` 6. **测试**:编写单元测试验证BLoC的行为 ```dart void main() { group('CounterBloc', () { late CounterBloc bloc; setUp(() { bloc = CounterBloc(); }); tearDown(() { bloc.close(); }); test('initial state is 0', () { expect(bloc.state, equals(0)); }); blocTest<CounterBloc, int>( 'emits [1] when IncrementPressed is added', build: () => bloc, act: (bloc) => bloc.add(IncrementPressed()), expect: () => [1], ); }); } ``` ## 总结 BLoC模式是Flutter中强大的状态管理解决方案,它具有以下优点: 1. 清晰的代码分层 2. 可预测的单向数据流 3. 易于测试和维护 4. 适合处理复杂的业务逻辑 建议: - 在小型应用中,可以使用Provider或setState - 中大型应用推荐使用BLoC模式 - 注意及时释放资源,避免内存泄漏 - 保持BLoC的简单性,避免过度设计