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

Riverpod中ref初始化异常:LateInitializationError问题求助

解决Riverpod中调用ref.read时的LateInitializationError问题

问题场景

执行if (!ref.read(userDataProvider).userType.isPremium)代码段时,出现错误:

Unhandled Exception: LateInitializationError: Field '_element@103511' has not been initialized

已确认userDataProvider完成初始化,但错误仍存在。

相关代码

banner_ad_notifier.dart

// Package imports:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:pin_share/constant/constant.dart';
// Project imports:
import 'package:pin_share/riverpod/banner/banner.dart';
import 'package:pin_share/riverpod/user/user.dart';

final mapBannerAdProvider =
    NotifierProvider<BannerAdNotifier, BannerAdState>(() {
  final bannerAdProvider = BannerAdNotifier()..loadBanner();
  return bannerAdProvider;
});

class BannerAdNotifier extends Notifier<BannerAdState> {
  @override
  BannerAdState build() {
    return const BannerAdState(bannerAd: null);
  }

  Future<void> loadBanner() async {
    if (!ref.read(userDataProvider).userType.isPremium) {
      await BannerAd(
        adUnitId: bannerAdUnitId,
        request: const AdRequest(),
        size: AdSize.banner,
        listener: BannerAdListener(
          onAdLoaded: (ad) {
            state = state.copyWith(bannerAd: ad as BannerAd);
          },
          onAdFailedToLoad: (ad, err) {
            ad.dispose();
          },
        ),
      ).load();
    }
  }
}

user_data_provider.dart

final userDataProvider = NotifierProvider<UserDataNotifier, UserDataState>(() {
  return UserDataNotifier();
});

错误原因

问题出在mapBannerAdProvider的初始化逻辑:你在BannerAdNotifier实例刚创建时就直接调用loadBanner(),此时Notifier还未被Riverpod完全初始化,内部的ref对象属于late初始化字段,只有在build()方法执行后才会被Riverpod注入实例,提前访问ref.read()必然触发初始化错误。

修复方案

方案1:将初始化逻辑移至build()方法

把loadBanner()的调用放到build()方法中,此时ref已完成注入:

class BannerAdNotifier extends Notifier<BannerAdState> {
  @override
  BannerAdState build() {
    // 用postFrameCallback确保UI初始化完成后再加载广告
    WidgetsBinding.instance.addPostFrameCallback((_) => loadBanner());
    return const BannerAdState(bannerAd: null);
  }

  Future<void> loadBanner() async {
    if (!ref.read(userDataProvider).userType.isPremium) {
      await BannerAd(
        adUnitId: bannerAdUnitId,
        request: const AdRequest(),
        size: AdSize.banner,
        listener: BannerAdListener(
          onAdLoaded: (ad) {
            state = state.copyWith(bannerAd: ad as BannerAd);
          },
          onAdFailedToLoad: (ad, err) {
            ad.dispose();
          },
        ),
      ).load();
    }
  }
}

同时修改mapBannerAdProvider的初始化,去掉构造函数里的loadBanner()调用:

final mapBannerAdProvider =
    NotifierProvider<BannerAdNotifier, BannerAdState>(BannerAdNotifier.new);

方案2:使用Riverpod的onMounted生命周期(Riverpod 2.0+)

如果项目使用Riverpod 2.0及以上版本,可利用Notifier的onMounted方法,它会在Notifier初始化完成、ref可用时自动触发:

class BannerAdNotifier extends Notifier<BannerAdState> {
  @override
  BannerAdState build() {
    // 注册初始化回调
    onMounted(() => loadBanner());
    return const BannerAdState(bannerAd: null);
  }

  Future<void> loadBanner() async {
    if (!ref.read(userDataProvider).userType.isPremium) {
      await BannerAd(
        adUnitId: bannerAdUnitId,
        request: const AdRequest(),
        size: AdSize.banner,
        listener: BannerAdListener(
          onAdLoaded: (ad) {
            state = state.copyWith(bannerAd: ad as BannerAd);
          },
          onAdFailedToLoad: (ad, err) {
            ad.dispose();
          },
        ),
      ).load();
    }
  }
}

mapBannerAdProvider的初始化同方案1:

final mapBannerAdProvider =
    NotifierProvider<BannerAdNotifier, BannerAdState>(BannerAdNotifier.new);

方案3:监听用户状态变化动态处理广告

如果用户会员状态可能在运行时改变,可监听userDataProvider的变化,自动触发广告加载或销毁:

class BannerAdNotifier extends Notifier<BannerAdState> {
  @override
  BannerAdState build() {
    // 监听用户数据变化,动态更新广告状态
    ref.listen<UserDataState>(userDataProvider, (previous, next) {
      if (!next.userType.isPremium) {
        loadBanner();
      } else {
        // 用户变为会员时,销毁已加载的广告
        state.bannerAd?.dispose();
        state = const BannerAdState(bannerAd: null);
      }
    });

    // 初始加载广告
    WidgetsBinding.instance.addPostFrameCallback((_) => loadBanner());
    return const BannerAdState(bannerAd: null);
  }

  Future<void> loadBanner() async {
    // 先销毁旧广告,避免内存泄漏
    state.bannerAd?.dispose();
    
    if (!ref.read(userDataProvider).userType.isPremium) {
      await BannerAd(
        adUnitId: bannerAdUnitId,
        request: const AdRequest(),
        size: AdSize.banner,
        listener: BannerAdListener(
          onAdLoaded: (ad) {
            state = state.copyWith(bannerAd: ad as BannerAd);
          },
          onAdFailedToLoad: (ad, err) {
            ad.dispose();
          },
        ),
      ).load();
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:52:33