Flutter 2.0.5使用Riverpod时StateNotifierProvider类型报错及读取异常问题
问题场景
开发Flutter 2.0.5版本应用时,计划采用Riverpod做状态管理,最初按如下方式定义StateNotifierProvider:
import 'package:flutter_riverpod/flutter_riverpod.dart'; final counterProvider = StateNotifierProvider<CounterStateNotifier>((ref) => CounterStateNotifier()); class CounterStateNotifier extends StateNotifier<int> { CounterStateNotifier([int count = 0]) : super(count); void increment() => state++; }
编译时Android Studio和Dart编译器会在counterProvider定义行抛出错误:The type 'StateNotifierProvider' is declared with 2 type parameters, but 1 type arguments were given.
尝试移除StateNotifierProvider后面跟的<CounterStateNotifier>类型参数后,编译报错消失,但运行时给ElevatedButton设置回调() => context.read(counterProvider).increment()触发点击时,会抛出运行时错误:
'increment' method not found Receiver: 0 Arguments: []
应用通过flutter run -d Chrome运行在Web端,核心待解决的两个问题:
- 移除类型参数后,为什么
context.read(counterProvider)读到的是int类型状态值,而不是对应的StateNotifier实例 - 最初类型参数不匹配的编译错误的根本原因
问题根因说明
编译报错的根本原因
当前使用的flutter_riverpod版本中,StateNotifierProvider的泛型签名是固定的双参数结构,完整定义为:
StateNotifierProvider<NotifierT extends StateNotifier<StateT>, StateT>
两个泛型参数分别为:
- 第一个:自定义的、继承自StateNotifier的类类型,也就是示例中的
CounterStateNotifier - 第二个:这个StateNotifier内部管理的状态值类型,也就是示例中的
int
最初的代码只传了第一个泛型参数CounterStateNotifier,缺失了代表状态类型的第二个参数,才会触发“声明带2个类型参数,但只传入1个”的编译错误。
移除泛型后读取值异常的原因
当你手动移除<CounterStateNotifier>泛型声明后,Dart的类型推断逻辑会自动推导Provider的完整泛型:
函数返回值是CounterStateNotifier,而CounterStateNotifier继承自StateNotifier<int>,此时类型推断会自动将Provider的暴露类型收敛为状态值类型int,而非StateNotifier实例本身。
结合Riverpod的默认设计逻辑:StateNotifierProvider的context.read()方法,默认拿到的从来不是StateNotifier实例,而是它持有的当前状态值。所以此时执行context.read(counterProvider)返回的就是初始状态值0,自然找不到increment方法,触发了你看到的运行时错误。
正确实现方式
完整传入两个泛型参数即可正常定义Provider:
// 两个泛型分别对应:自定义StateNotifier类型、管理的状态值类型 final counterProvider = StateNotifierProvider<CounterStateNotifier, int>((ref) => CounterStateNotifier());
如果需要拿到StateNotifier实例调用内部方法,需要通过.notifier属性获取实例,直接读取Provider拿到的始终是状态值:
ElevatedButton( onPressed: () => context.read(counterProvider.notifier).increment(), )
注意:直接通过
context.read(counterProvider)获取状态值、通过.notifier获取操作方法,是StateNotifierProvider的标准使用方式,属于框架设计预期,并非异常。
内容的提问来源于stack exchange,提问作者Giorgio

