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

Flutter Bloc获取前一状态:计时器重置保留自定义时长方案咨询

解决Flutter Bloc计时器重置时自定义时长被覆盖的问题

你当前的问题核心是维护了私有变量_duration作为时长存储,这违背了Bloc“状态为唯一可信数据源”的设计原则,导致重置时依赖私有变量而非当前状态,自然会出现自定义时长被覆盖的问题。下面是更简洁且符合Bloc规范的解决方案:

核心思路

将用户设置的自定义时长完全托管在Bloc的状态中,移除私有变量_duration,所有操作(包括重置)都从当前状态读取基准时长,确保状态是唯一的数据源。

步骤1:调整状态结构,添加基准时长属性

修改TimerState抽象类,让所有状态都携带baseDuration(用户设置的自定义时长),确保任何状态下都能访问到这个基准值:

abstract class TimerState extends Equatable {
  final int duration; // 当前剩余时长
  final int baseDuration; // 用户设置的基准时长

  const TimerState(this.duration, this.baseDuration);

  @override
  List<Object> get props => [duration, baseDuration];
}

// 初始状态:显示基准时长
class TimerInitial extends TimerState {
  const TimerInitial(int baseDuration) : super(baseDuration, baseDuration);
}

// 运行中状态:显示剩余时长+保存基准时长
class TimerRunInProgress extends TimerState {
  const TimerRunInProgress(int duration, int baseDuration) : super(duration, baseDuration);
}

// 暂停状态:显示暂停时的剩余时长+保存基准时长
class TimerRunPause extends TimerState {
  const TimerRunPause(int duration, int baseDuration) : super(duration, baseDuration);
}

// 完成状态:剩余时长为0+保存基准时长
class TimerRunComplete extends TimerState {
  const TimerRunComplete(int baseDuration) : super(0, baseDuration);
}

步骤2:重构TimerBloc,移除私有变量并基于状态操作

去掉_duration私有变量,所有逻辑都依赖当前状态的baseDuration:

class TimerBloc extends Bloc<TimerEvent, TimerState> {
  final Ticker _ticker;
  StreamSubscription<int>? _tickerSubscription;

  // 初始化时仅传入初始基准时长,直接作为初始状态
  TimerBloc({required Ticker ticker, required int initialDuration})
      : _ticker = ticker,
        super(TimerInitial(initialDuration)) {
    on<TimerStarted>(_onStarted);
    on<_TimerTicked>(_onTicked);
    on<TimerPaused>(_onPaused);
    on<TimerResumed>(_onResumed);
    on<TimerReset>(_onReset);
    on<TimerChanged>(_onChanged);
  }

  @override
  Future<void> close() {
    _tickerSubscription?.cancel();
    return super.close();
  }

  void _onStarted(TimerStarted event, Emitter<TimerState> emit) {
    // 运行时携带当前基准时长
    emit(TimerRunInProgress(event.duration, state.baseDuration));
    _tickerSubscription?.cancel();
    _tickerSubscription = _ticker
        .tick(ticks: event.duration)
        .listen((duration) => add(_TimerTicked(duration: duration)));
  }

  void _onTicked(_TimerTicked event, Emitter<TimerState> emit) {
    emit(
      event.duration > 0
          ? TimerRunInProgress(event.duration, state.baseDuration)
          : TimerRunComplete(state.baseDuration),
    );
  }

  void _onPaused(TimerPaused event, Emitter<TimerState> emit) {
    if (state is TimerRunInProgress) {
      _tickerSubscription?.pause();
      emit(TimerRunPause(state.duration, state.baseDuration));
    }
  }

  void _onReset(TimerReset event, Emitter<TimerState> emit) {
    _tickerSubscription?.cancel();
    // 重置时直接取当前状态的基准时长,而非私有变量
    emit(TimerInitial(state.baseDuration));
  }

  void _onResumed(TimerResumed event, Emitter<TimerState> emit) {
    if (state is TimerRunPause) {
      _tickerSubscription?.resume();
      emit(TimerRunInProgress(state.duration, state.baseDuration));
    }
  }

  void _onChanged(TimerChanged event, Emitter<TimerState> emit) {
    // 修改时长时直接更新初始状态,将新时长作为基准
    emit(TimerInitial(event.duration));
  }
}

方案优势

  1. 符合Bloc设计规范:状态是唯一的可信数据源,避免了私有变量与状态不一致的问题
  2. 逻辑简洁清晰:重置操作直接读取当前状态的基准时长,不会被初始默认值覆盖
  3. 状态可追溯:所有状态都携带基准时长,任何操作都能基于当前状态正确执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 10:12:11