Riverpod vs Bloc 对比

以最少代码实现编译期安全、快速演进的 provider 架构

VS
Bloc

强制事件/状态流转的成熟架构,社区规模庞大

10 分钟阅读Cross-Platform

快速结论

没有"错误的选择"——两者都经过验证,且都采用 MIT 许可证。1-5 人的小团队、追求快速迭代时选 Riverpod:样板代码少,代码生成可选,版本发布节奏非常活跃(3.4.3,2026-09-03)。多团队协作、需要可审计事件流的企业级项目选 Bloc:事件/状态分离是强制的,有 BlocObserver,但 flutter_bloc 的最新版本停留在 2025-05-02——需要持续关注。问题不是"哪个更好",而是"你希望多少纪律由外部强制"。

RiverpodBloc
阅读完整结论

评分对比

图表加载中…

详细评分

详细评分: Riverpod Bloc ——按类别打分,满分 10 分
分类RiverpodBloc
性能
8/10
8/10
学习难易度
8/10
6/10
生态系统
7/10
9/10
社区
7/10
9/10
就业市场
7/10
7/10
面向未来
8/10
7/10

优缺点

Riverpod

优点

  • 代码生成完全可选——也可以用经典语法编写
  • 围绕单一概念(Provider/Ref)构建,学习曲线低
  • 通过 ProviderContainer.test() 无需额外依赖包即可实现隔离的单元测试
  • 读取 provider 无需依赖 BuildContext
  • DevTools 插件随 riverpod 包一同提供(extension/devtools,v1.0.0)
  • Riverpod 3.0 引入实验性 mutations 以及 riverpod_sqflite 离线持久化
  • pub.dev 上月下载量达 2,970,654 次,活跃使用率高
  • 2026-09-03 发布 3.4.3 版本,开发节奏非常活跃

缺点

  • 经典语法与代码生成语法之间该选哪种,需要团队自行决定
  • GitHub 星标(7,375)落后于 Bloc——社区相对年轻
  • pub.dev pub point(140/160)落后于 Bloc 的满分
  • 不强制架构契约——大团队中的一致性依赖团队自身纪律
  • 使用代码生成时会形成对 build_runner 工具链的依赖
  • 不依赖代码生成的统一语法目前仍处于 RFC 阶段,尚未稳定

最适合

1-5 人的小团队及快速 MVP/初创项目迭代已经在使用 Freezed 或 json_serializable 的项目需要离线优先或实验性 state mutation 能力的应用希望以少量样板代码和单一概念快速上手的团队优先考虑活跃、持续更新的依赖链的项目

Bloc

优点

  • 强制事件/状态分离——不可能从任意地方修改 state
  • 通过 BlocObserver 可以集中记录每一次 state 转换
  • 官方文档明确定义了三层架构(Presentation/Business Logic/Data)
  • pub.dev 上获得 160/160 满分 pub point,以及官方"Flutter Favorite"徽章
  • GitHub 上 12,482 星标,社区更大更成熟
  • 通过 blocTest 以 build/act/expect 模式编写一致且可读的测试
  • 官方支持 Bloc-to-Bloc Communication,支持多层、多 repository 的组合方式
  • 在 pub.dev 上带有 wasm-ready 和 platform:web 标签,Web 端支持成熟

缺点

  • 即使是简单界面,也需要编写独立的 event/state 类
  • 需要学习 bloc_test 包以及独立的测试 DSL(blocTest)
  • flutter_bloc 最新版本发布于 2025-05-02——已超过 16 个月未更新
  • 没有基于 build_runner 的官方代码生成器;减少样板代码依赖官方 IntelliJ/VSCode 插件的模板生成功能
  • 对 provider 包(BlocProvider 的基础)存在无法移除的结构性依赖
  • 官方文档中 Repository/DataProvider 构造函数的搭建方式没有清晰的示例

最适合

10 人以上、多模块的企业级项目需要可审计性/合规性的受监管行业(金融科技、医疗等)以初级开发者为主、需要强制架构契约的团队希望在代码评审中自动保证测试一致性的团队希望依托长期、成熟且庞大社区的项目

代码对比

Riverpod
// Riverpod - 用户列表(使用代码生成)
// 来源:riverpod.dev 官方文档模式
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'user_list_provider.g.dart';

@riverpod
Future<List<User>> userList(Ref ref, {required int page}) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.fetchUsers(page: page);
}

class UserListScreen extends ConsumerWidget {
  const UserListScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final usersAsync = ref.watch(userListProvider(page: 1));

    return usersAsync.when(
      data: (users) => ListView.builder(
        itemCount: users.length,
        itemBuilder: (context, index) => ListTile(
          title: Text(users[index].name),
          subtitle: Text(users[index].email),
        ),
      ),
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (error, stack) => Center(child: Text('错误:$error')),
    );
  }
}

// 不使用代码生成的经典语法替代方案(官方文档,可选):
final userListClassicProvider =
    FutureProvider.autoDispose.family<List<User>, int>((ref, page) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.fetchUsers(page: page);
});
Bloc
// Bloc - 用户列表(Event/State + Repository)
// 来源:bloclibrary.dev 官方 Core Concepts 模式
import 'package:flutter_bloc/flutter_bloc.dart';

sealed class UserListEvent {}

class FetchUsers extends UserListEvent {
  FetchUsers({required this.page});
  final int page;
}

sealed class UserListState {}

class UserListInitial extends UserListState {}

class UserListLoading extends UserListState {}

class UserListLoaded extends UserListState {
  UserListLoaded({required this.users});
  final List<User> users;
}

class UserListError extends UserListState {
  UserListError({required this.message});
  final String message;
}

class UserListBloc extends Bloc<UserListEvent, UserListState> {
  UserListBloc({required this.repository}) : super(UserListInitial()) {
    on<FetchUsers>(_onFetchUsers);
  }

  final UserRepository repository;

  Future<void> _onFetchUsers(
    FetchUsers event,
    Emitter<UserListState> emit,
  ) async {
    emit(UserListLoading());
    try {
      final users = await repository.fetchUsers(page: event.page);
      emit(UserListLoaded(users: users));
    } catch (error) {
      emit(UserListError(message: error.toString()));
    }
  }
}

结论

没有"错误的选择"——两者都经过验证,且都采用 MIT 许可证。1-5 人的小团队、追求快速迭代时选 Riverpod:样板代码少,代码生成可选,版本发布节奏非常活跃(3.4.3,2026-09-03)。多团队协作、需要可审计事件流的企业级项目选 Bloc:事件/状态分离是强制的,有 BlocObserver,但 flutter_bloc 的最新版本停留在 2025-05-02——需要持续关注。问题不是"哪个更好",而是"你希望多少纪律由外部强制"。

获取免费咨询
常见问题

常见问题

没有唯一正确答案。如果你的团队只有 1-5 人、追求快速迭代,并且架构决策可以靠团队内部沟通解决,Riverpod(样板代码少、代码生成可选、无需 BuildContext 即可测试)更合适。如果是多团队协作、需要可审计事件流和严格契约的企业级项目(例如金融科技、医疗等受监管行业),Bloc 通过强制事件/状态分离以及 BlocObserver 的集中式日志记录,提供了更安全的基础。

相关博客文章

查看全部文章

相关项目

查看全部项目
全部对比