如何基于riverpod_generator构建全局SharedPreferences 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
相关产品推荐
相关产品推荐

