如何用Flutter Bloc结合Clean架构实现全局状态管理与列表操作?
基于Flutter Bloc + Clean架构实现全局任务状态管理
1. 依赖准备
在pubspec.yaml中添加必要依赖:
dependencies: flutter: sdk: flutter flutter_bloc: ^8.1.3 equatable: ^2.0.5
2. 实体层(Entity)
纯业务对象,仅包含核心属性和业务行为,不依赖任何框架:
// lib/entities/task_entity.dart class TaskEntity { final String title; final bool isDone; const TaskEntity({required this.title, this.isDone = false}); // 切换完成状态的业务方法 TaskEntity toggleDone() { return TaskEntity(title: title, isDone: !isDone); } }
3. 模型层(Model)
负责实体与外部数据(如本地存储、API)的转换,这里先做基础映射:
// lib/models/task_model.dart import '../entities/task_entity.dart'; class TaskModel extends TaskEntity { const TaskModel({required super.title, super.isDone = false}); // 实体转模型 factory TaskModel.fromEntity(TaskEntity entity) { return TaskModel(title: entity.title, isDone: entity.isDone); } // 模型转实体 TaskEntity toEntity() { return TaskEntity(title: title, isDone: isDone); } }
4. 仓库层(Repository)
封装数据来源,统一对外提供数据操作接口,这里先模拟内存数据:
// lib/repositories/task_repository.dart import '../entities/task_entity.dart'; class TaskRepository { List<TaskEntity> _tasks = [ const TaskEntity(title: 'Buy Milk'), const TaskEntity(title: 'Buy Eggs'), const TaskEntity(title: 'Buy Bread'), ]; // 获取不可修改的任务列表 List<TaskEntity> getTasks() { return List.unmodifiable(_tasks); } // 添加任务 void addTask(String title) { _tasks.add(TaskEntity(title: title)); } // 切换任务完成状态 void toggleTaskDone(int index) { _tasks[index] = _tasks[index].toggleDone(); } // 删除任务 void removeTask(int index) { _tasks.removeAt(index); } }
5. Bloc业务逻辑层
分为事件(Event)、状态(State)和Bloc核心处理类,实现状态流转。
5.1 任务事件定义
// lib/blocs/task/task_events.dart import 'package:equatable/equatable.dart'; abstract class TaskEvent extends Equatable { const TaskEvent(); @override List<Object> get props => []; } // 添加任务事件 class AddTask extends TaskEvent { final String title; const AddTask(this.title); @override List<Object> get props => [title]; } // 切换任务完成状态事件 class ToggleTaskDone extends TaskEvent { final int index; const ToggleTaskDone(this.index); @override List<Object> get props => [index]; } // 删除任务事件 class RemoveTask extends TaskEvent { final int index; const RemoveTask(this.index); @override List<Object> get props => [index]; } // 初始化加载任务事件 class LoadTasks extends TaskEvent {}
5.2 任务状态定义
// lib/blocs/task/task_states.dart import 'package:equatable/equatable.dart'; import '../../entities/task_entity.dart'; abstract class TaskState extends Equatable { const TaskState(); @override List<Object> get props => []; } // 加载中状态 class TasksLoading extends TaskState {} // 加载完成状态 class TasksLoaded extends TaskState { final List<TaskEntity> tasks; const TasksLoaded(this.tasks); @override List<Object> get props => [tasks]; }
5.3 Bloc核心逻辑处理
// lib/blocs/task/task_bloc.dart import 'package:flutter_bloc/flutter_bloc.dart'; import 'task_events.dart'; import 'task_states.dart'; import '../../repositories/task_repository.dart'; class TaskBloc extends Bloc<TaskEvent, TaskState> { final TaskRepository repository; TaskBloc(this.repository) : super(TasksLoading()) { // 绑定事件处理逻辑 on<LoadTasks>(_onLoadTasks); on<AddTask>(_onAddTask); on<ToggleTaskDone>(_onToggleTaskDone); on<RemoveTask>(_onRemoveTask); // 初始化时加载任务 add(LoadTasks()); } void _onLoadTasks(LoadTasks event, Emitter<TaskState> emit) { final tasks = repository.getTasks(); emit(TasksLoaded(tasks)); } void _onAddTask(AddTask event, Emitter<TaskState> emit) { repository.addTask(event.title); final tasks = repository.getTasks(); emit(TasksLoaded(tasks)); } void _onToggleTaskDone(ToggleTaskDone event, Emitter<TaskState> emit) { repository.toggleTaskDone(event.index); final tasks = repository.getTasks(); emit(TasksLoaded(tasks)); } void _onRemoveTask(RemoveTask event, Emitter<TaskState> emit) { repository.removeTask(event.index); final tasks = repository.getTasks(); emit(TasksLoaded(tasks)); } }
6. 全局注入Bloc
在应用根节点通过BlocProvider提供全局可访问的Bloc实例:
// lib/main.dart import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'blocs/task/task_bloc.dart'; import 'repositories/task_repository.dart'; import 'screens/tasks_screen.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => TaskBloc(TaskRepository()), child: MaterialApp( theme: ThemeData(useMaterial3: true), home: const TasksScreen(), ), ); } }
7. UI层使用Bloc
通过BlocBuilder监听状态变化,渲染UI并发送事件。
7.1 任务列表组件
// lib/screens/tasks_list.dart import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../blocs/task/task_bloc.dart'; import '../blocs/task/task_events.dart'; import '../blocs/task/task_states.dart'; import '../widgets/task_tile.dart'; class TasksList extends StatelessWidget { const TasksList({super.key}); @override Widget build(BuildContext context) { return BlocBuilder<TaskBloc, TaskState>( builder: (context, state) { if (state is TasksLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is TasksLoaded) { return ListView.builder( itemCount: state.tasks.length, itemBuilder: (context, index) { final task = state.tasks[index]; return TaskTile( taskTitle: task.title, isChecked: task.isDone, checkboxCallback: (newValue) { context.read<TaskBloc>().add(ToggleTaskDone(index)); }, listTileCallback: () { context.read<TaskBloc>().add(RemoveTask(index)); }, ); }, ); } else { return const Center(child: Text('暂无任务')); } }, ); } }
7.2 主页面(含添加任务功能)
// lib/screens/tasks_screen.dart import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../blocs/task/task_bloc.dart'; import '../blocs/task/task_events.dart'; import 'tasks_list.dart'; class TasksScreen extends StatelessWidget { const TasksScreen({super.key}); @override Widget build(BuildContext context) { final textController = TextEditingController(); return Scaffold( appBar: AppBar(title: const Text('任务列表')), body: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: TextField( controller: textController, decoration: const InputDecoration(hintText: '输入新任务'), ), ), IconButton( onPressed: () { if (textController.text.isNotEmpty) { context.read<TaskBloc>().add(AddTask(textController.text)); textController.clear(); } }, icon: const Icon(Icons.add), ) ], ), ), const Expanded(child: TasksList()), ], ), ); } }
7.3 任务项组件
// lib/widgets/task_tile.dart import 'package:flutter/material.dart'; class TaskTile extends StatelessWidget { final String taskTitle; final bool isChecked; final Function(bool?)? checkboxCallback; final VoidCallback? listTileCallback; const TaskTile({ super.key, required this.taskTitle, required this.isChecked, this.checkboxCallback, this.listTileCallback, }); @override Widget build(BuildContext context) { return ListTile( title: Text( taskTitle, style: TextStyle(decoration: isChecked ? TextDecoration.lineThrough : null), ), trailing: Checkbox( value: isChecked, onChanged: checkboxCallback, ), onLongPress: listTileCallback, ); } }
核心说明
- 分层职责清晰:实体层处理业务逻辑,模型层做数据转换,仓库层封装数据源,Bloc层管理状态流转,UI层仅负责渲染和事件触发。
- 状态不可变:通过
Equatable确保状态变化可被Bloc正确识别,避免无效重绘。 - 全局访问:根节点注入的Bloc可被所有子组件通过
context.read()或BlocBuilder访问,实现全局状态共享。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

