公告

👇欢迎大家关注公众号&私信交流👇

Skip to content

Flutter Bloc 状态管理详解

简介

Bloc (Business Logic Component) 是一个基于事件驱动的状态管理模式,它将业务逻辑从UI层分离出来,使用事件(Event)和状态(State)来管理应用数据流。

基本概念

Event

dart
// 事件基类
abstract class CounterEvent {}

// 具体事件
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}

State

dart
// 状态基类
abstract class CounterState {
  final int count;
  const CounterState(this.count);
}

// 具体状态
class CounterInitial extends CounterState {
  CounterInitial() : super(0);
}

class CounterUpdated extends CounterState {
  CounterUpdated(int count) : super(count);
}

Bloc

dart
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterInitial()) {
    on<IncrementEvent>((event, emit) {
      emit(CounterUpdated(state.count + 1));
    });
    
    on<DecrementEvent>((event, emit) {
      emit(CounterUpdated(state.count - 1));
    });
  }
}

基本用法

提供 Bloc

dart
void main() {
  runApp(
    BlocProvider(
      create: (context) => CounterBloc(),
      child: MyApp(),
    ),
  );
}

使用 Bloc

dart
// 监听状态
BlocBuilder<CounterBloc, CounterState>(
  builder: (context, state) {
    return Text('Count: ${state.count}');
  },
);

// 发送事件
context.read<CounterBloc>().add(IncrementEvent());

完整示例

dart
// 用户相关事件
abstract class UserEvent {}

class LoadUserEvent extends UserEvent {}
class UpdateUserEvent extends UserEvent {
  final String name;
  final int age;
  
  UpdateUserEvent({required this.name, required this.age});
}

// 用户相关状态
abstract class UserState {}

class UserInitial extends UserState {}

class UserLoading extends UserState {}

class UserLoaded extends UserState {
  final String name;
  final int age;
  
  UserLoaded({required this.name, required this.age});
}

class UserError extends UserState {
  final String message;
  
  UserError(this.message);
}

// 用户 Bloc
class UserBloc extends Bloc<UserEvent, UserState> {
  final UserRepository repository;
  
  UserBloc({required this.repository}) : super(UserInitial()) {
    // 加载用户
    on<LoadUserEvent>((event, emit) async {
      emit(UserLoading());
      try {
        final user = await repository.getUser();
        emit(UserLoaded(name: user.name, age: user.age));
      } catch (e) {
        emit(UserError('Failed to load user: $e'));
      }
    });
    
    // 更新用户
    on<UpdateUserEvent>((event, emit) async {
      emit(UserLoading());
      try {
        await repository.updateUser(event.name, event.age);
        emit(UserLoaded(name: event.name, age: event.age));
      } catch (e) {
        emit(UserError('Failed to update user: $e'));
      }
    });
  }
}

// 页面组件
class UserPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Bloc Demo')),
      body: BlocBuilder<UserBloc, UserState>(
        builder: (context, state) {
          if (state is UserLoading) {
            return Center(child: CircularProgressIndicator());
          }
          
          if (state is UserError) {
            return Center(child: Text(state.message));
          }
          
          if (state is UserLoaded) {
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Name: ${state.name}',
                    style: TextStyle(fontSize: 24),
                  ),
                  Text(
                    'Age: ${state.age}',
                    style: TextStyle(fontSize: 24),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      context.read<UserBloc>().add(
                        UpdateUserEvent(
                          name: 'John Doe',
                          age: 30,
                        ),
                      );
                    },
                    child: Text('Update User'),
                  ),
                ],
              ),
            );
          }
          
          return Center(
            child: ElevatedButton(
              onPressed: () {
                context.read<UserBloc>().add(LoadUserEvent());
              },
              child: Text('Load User'),
            ),
          );
        },
      ),
    );
  }
}

高级用法

BlocListener

dart
BlocListener<UserBloc, UserState>(
  listener: (context, state) {
    if (state is UserError) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(state.message)),
      );
    }
  },
  child: YourWidget(),
)

BlocConsumer

dart
BlocConsumer<UserBloc, UserState>(
  listener: (context, state) {
    // 处理副作用
  },
  builder: (context, state) {
    // 构建UI
    return YourWidget();
  },
)

状态流转换

dart
Stream<State> transformEvents<Event, State>(
  Stream<Event> events,
  Stream<State> Function(Event event) mapper,
) {
  return events
    .debounceTime(Duration(milliseconds: 300))
    .switchMap(mapper);
}

最佳实践

  1. 合理划分事件和状态
  2. 使用密封类(sealed class)定义状态
  3. 保持 Bloc 的单一职责
  4. 合理处理异步操作
  5. 注意内存管理

注意事项

  1. 避免在 Bloc 中直接操作 UI
  2. 合理处理状态转换
  3. 注意事件处理的顺序
  4. 处理好异常情况
  5. 避免状态对象过大

总结

Bloc 提供了一种清晰的方式来管理应用状态,通过分离业务逻辑和UI表现层,可以构建出更易维护、测试的应用程序。理解并掌握 Bloc 的使用对于开发高质量的 Flutter 应用至关重要。