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

Flutter Bloc中布尔状态变量首次赋值后停止变更的问题排查

Flutter Bloc计时器应用isBreak值无法正常切换问题

我是Flutter新手,正在用Bloc开发一款交替进行工作和休息时段的计时器应用,通过SessionsBloc中的布尔值isBreak跟踪当前时段类型。预期每次触发SessionTrackingEvent时,isBreak能切换为相反值,但实际只有第一次从false变为true生效,之后不再变化。尝试过修改变量类型、调整状态读取逻辑,但问题依旧。


代码片段

1. SessionsState定义

part of 'sessions_bloc.dart';
abstract class SessionsState extends Equatable { 
  final bool isBreak; 
  final int sessionCount; 
  const SessionsState(this.isBreak, this.sessionCount);
  
  @override 
  List<Object> get props => []; 
}

class SessionsInitial extends SessionsState { 
  const SessionsInitial(super.isBreak, super.sessionCount); 
}

class SessionTrackingState extends SessionsState { 
  const SessionTrackingState(super.isBreak, super.sessionCount); 
}

2. BlocListener监听逻辑

listener: (context, state) {
  Task currentTask = BlocProvider.of<TasksBloc>(context).state.currentTask;
  bool isTimeBoxed = currentTask.isTimeBoxed;
  int sessionDuration;
  int breakDuration;
  if (state is TimerCompleteState) {
    // 获取SessionsBloc当前状态
    final sessionState = BlocProvider.of<SessionsBloc>(context).state;
    bool isBreak = sessionState.isBreak;
    int sessionCount = sessionState.sessionCount;
    
    print(sessionState.isBreak);
    print(sessionState.sessionCount);

    if (isTimeBoxed) {
      sessionDuration = currentTask.sessionTimeBox!;
      breakDuration = currentTask.breakTimeBox ?? 2;
      // sessionCount = HiveDb().getTaskSessionCount(currentTask.taskName);
    } else {
      sessionDuration = 5;
      breakDuration = 3;
    }

    if (isBreak) {
      BlocProvider.of<TimerBloc>(context)
          .add(InitializeTimerEvent(duration: sessionDuration));
      BlocProvider.of<SessionsBloc>(context).add(SessionTrackingEvent(
        isBreak: isBreak,
        sessionCount: sessionCount,
      ));
    } else {
      BlocProvider.of<TimerBloc>(context)
          .add(InitializeTimerEvent(duration: breakDuration));
      BlocProvider.of<TimerBloc>(context)
          .add(OnBreakEvent(duration: breakDuration));
      BlocProvider.of<SessionsBloc>(context).add(SessionTrackingEvent(
        isBreak: isBreak,
        sessionCount: sessionCount += 1,
      ));
    }
  }
},

3. SessionsBloc实现

class SessionsBloc extends Bloc<SessionsEvent, SessionsState> {
  SessionsBloc() : super(const SessionsInitial(false, 0)) {
    on<SessionTrackingEvent>((event, emit) {
      emit(SessionTrackingState(
          event.isBreak ? false : true, event.sessionCount));
    });
  }
}

问题根源

  1. Equatable未正确重写props:SessionsState继承了Equatable,但props返回空列表,导致Bloc无法判断状态是否发生变化。当emit新状态时,Bloc会对比新旧状态的props,若完全一致则不会触发UI更新,后续读取状态也无法获取最新值。

  2. 事件处理依赖旧值而非当前状态:当前SessionTrackingEvent携带的是触发事件时读取的旧isBreak值,SessionsBloc处理事件时直接基于这个旧值切换。这种依赖外部传递参数的方式容易导致状态不同步,正确的做法应该是让Bloc基于自身当前状态计算新值。


修复步骤

步骤1:修正Equatable的props

修改SessionsState的props,将isBreak和sessionCount加入列表,确保Bloc能正确识别状态变化:

abstract class SessionsState extends Equatable { 
  final bool isBreak; 
  final int sessionCount; 
  const SessionsState(this.isBreak, this.sessionCount);
  
  @override 
  List<Object> get props => [isBreak, sessionCount]; // 加入状态字段
}

步骤2:优化SessionsBloc的事件处理逻辑

简化SessionTrackingEvent(不需要传递参数,让Bloc自行维护状态):

class SessionTrackingEvent extends SessionsEvent {
  const SessionTrackingEvent();
}

修改SessionsBloc的事件处理逻辑,基于当前状态计算新值:

class SessionsBloc extends Bloc<SessionsEvent, SessionsState> {
  SessionsBloc() : super(const SessionsInitial(false, 0)) {
    on<SessionTrackingEvent>((event, emit) {
      // 获取当前状态的字段值
      final currentIsBreak = state.isBreak;
      final currentSessionCount = state.sessionCount;
      
      // 切换isBreak,非休息时段则sessionCount+1
      final newIsBreak = !currentIsBreak;
      final newSessionCount = currentIsBreak ? currentSessionCount : currentSessionCount + 1;
      
      emit(SessionTrackingState(newIsBreak, newSessionCount));
    });
  }
}

步骤3:调整BlocListener中的事件触发

因为事件不再需要传递参数,修改listener中的调用:

// 替换原来带参数的调用
BlocProvider.of<SessionsBloc>(context).add(const SessionTrackingEvent());

内容的提问来源于stack exchange,提问作者Murithi Vin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:45:34