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

如何基于riverpod_generator构建全局SharedPreferences Provider?

基于riverpod_generator实现全局SharedPreferences Provider及跨Provider引用

原代码存在的问题

  • 全局SharedPreferences Provider中,build方法直接返回未初始化的late SharedPreferences _sharedPreferences,未正确异步获取实例,会触发运行时空指针异常。
  • 引用Provider时,在类成员位置直接调用ref.read(sharedPrefProvider.notifier)不符合Riverpod生命周期规则,ref仅能在build方法或Provider内部方法中使用。

最优实现方案

1. 全局SharedPreferences Provider

使用AsyncNotifier处理异步获取SharedPreferences的逻辑,适配异步状态管理:

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';

part 'shared_pref_provider.g.dart';

const _pinKey = 'user_pin';

@riverpod
class SharedPref extends _$SharedPref {
  @override
  Future<SharedPreferences> build() async {
    // 异步初始化SharedPreferences实例
    return await SharedPreferences.getInstance();
  }

  // 获取存储的PIN码
  int? getPin() {
    // 确保状态已加载完成,若需处理加载/错误状态可使用state.maybeWhen
    return state.requireValue.getInt(_pinKey);
  }

  // 存储PIN码
  Future<void> setPin(int? pinNumber) async {
    if (pinNumber == null) return;
    await state.requireValue.setInt(_pinKey, pinNumber);
    // 若需通知依赖组件刷新,可调用ref.invalidateSelf()
  }

  // 删除PIN码
  Future<void> removePin() async {
    await state.requireValue.remove(_pinKey);
  }

  // 清空所有存储数据
  Future<void> deleteAll() async {
    await state.requireValue.clear();
  }
}

2. 跨Provider引用SharedPreferences Provider

在目标Provider中,通过build方法监听或方法内读取的方式引用:

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter/foundation.dart';
import 'shared_pref_provider.dart';

part 'setting_pin_provider.g.dart';

// 自定义状态类
@immutable
class SomeDataState {
  final int? pin;

  const SomeDataState({this.pin});

  SomeDataState copyWith({int? pin}) {
    return SomeDataState(pin: pin ?? this.pin);
  }
}

@riverpod
class SettingPin extends _$SettingPin {
  @override
  SomeDataState build() {
    // 监听SharedPreferences状态,同步已存储的PIN到当前状态
    final sharedPrefState = ref.watch(sharedPrefProvider);
    final savedPin = sharedPrefState.when(
      data: (pref) => pref.getInt(_pinKey),
      loading: () => null,
      error: (_, __) => null,
    );
    return SomeDataState(pin: savedPin);
  }

  void setUpAPin(int? number) {
    // 在方法内读取SharedPref的notifier并调用方法
    final sharedPrefNotifier = ref.read(sharedPrefProvider.notifier);
    sharedPrefNotifier.setPin(number);
    // 更新当前Provider状态以同步UI
    state = state.copyWith(pin: number);
  }
}

必要操作与注意事项

  • 生成代码:执行dart run build_runner watch命令自动生成.g.dart后缀的代码文件,这是riverpod_generator的核心要求。
  • 异步状态处理:AsyncNotifier的state为AsyncValue类型,使用时需覆盖加载、错误、成功三种状态,避免直接调用requireValue导致崩溃。
  • ref的使用规则:ref只能在Provider的build方法或内部方法中调用,禁止在类成员初始化阶段使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:55:22