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

Riverpod+Freezed下合并FutureProviders到StateNotifierProvider重复实例问题

重复实例问题根因

你在StateNotifierProvider的创建回调中直接使用ref.watch监听两个FutureProvider,任意一个FutureProvider状态更新时,都会触发创建回调重新执行,生成新的ClockingNotifier实例,因此init方法会被多次调用。

修复方案

不要在创建回调中直接传入watch的结果,改为将ref传入ClockingNotifier内部,使用ref.listen监听两个FutureProvider的状态变化,listen仅会触发回调逻辑,不会导致StateNotifierProvider重建生成新实例。

完整实现代码

import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final clockingState = StateNotifierProvider<ClockingNotifier, ClockingState>(
  (ref) => ClockingNotifier(ref)
);

class ClockingNotifier extends StateNotifier<ClockingState> {
  final Ref ref;
  Timer? _countdownTimer;
  // 标记DPS数据是否已加载完成
  bool _dpsLoaded = false;
  // 缓存加载完成的DPS数据
  ClockingState? _cachedDpsState;

  ClockingNotifier(this.ref) : super(ClockingState.init()) {
    init();
  }

  void init() {
    logger.d("the init method");
    // 监听行程加载Provider
    ref.listen<AsyncValue<ClockingState>>(loadingItineraryProvider, (previous, next) {
      next.when(
        loading: () => state = ClockingState.loading(),
        error: (e, s) => state = ClockingState.error(e),
        data: (clockingState) {
          logger.d("clocking state");
          // DPS未加载完成时才展示行程状态
          if (!_dpsLoaded) {
            state = clockingState;
          }
        },
      );
    });

    // 监听DPS数据Provider
    ref.listen<AsyncValue<ClockingState>>(clockingDps, (previous, next) {
      next.when(
        loading: () {}, // 加载中不修改状态,保持行程展示
        error: (e, s) => state = ClockingState.error(e),
        data: (dpsState) {
          logger.d("DPS state");
          _cachedDpsState = dpsState;
          _dpsLoaded = true;
          // 启动10秒倒计时
          _countdownTimer?.cancel();
          _countdownTimer = Timer(const Duration(seconds: 10), () {
            state = _cachedDpsState!;
          });
        },
      );
    });
  }

  @override
  void dispose() {
    _countdownTimer?.cancel();
    super.dispose();
  }
}

逻辑说明

  1. Notifier全程仅初始化一次,init方法只会执行一次,不会出现重复实例问题
  2. 行程数据加载完成后直接渲染,作为加载页展示
  3. DPS数据加载完成后缓存数据,启动10秒倒计时,倒计时结束后再切换为DPS状态
  4. 两个Provider的错误状态都会同步到页面,也可以根据业务需求自定义错误处理逻辑
  5. 组件销毁时自动取消定时器,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:18:00