You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 13:37:58