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

泛型ChangeNotifier子类传函数参数引发Provider查找失败,如何解决?

问题描述

尝试编写基于ChangeNotifier的泛型Provider类MapProvider,因类内数据为泛型类型,将ID提取函数作为构造函数参数传入。相关代码如下:

MapProvider类定义

class MapProvider<T> with ChangeNotifier {
  String Function(T) idExtract;

  List<T> _locationList = [];
  T? _selectedLocation;

  MapProvider(this.idExtract);
  // 其他方法省略
}

MultiProvider中的使用

return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => MapProvider(
            (pin) => (pin as ILocationPin).id,
          ),
        ),
      ],
      child: MapConsumerWidget()
    )

消费Provider的代码

final mapProvider = Provider.of<MapProvider>(context, listen: false);
final providerState = Provider.of<MapProvider>(context);
final selectedPin = providerState.selectedLocation;
final locationList = providerState.locationList;

运行时出现红屏错误:

Error: Could not find the correct Provider<MapProvider<dynamic>> above this MapConsumerWrapper widget.

但将idExtract改为返回int等基本类型时代码可正常运行,请问原因是什么?该如何解决?

错误原因
  • 泛型类型推断丢失:创建MapProvider实例时未显式指定泛型参数T,Dart会将T推断为dynamic,此时注册的Provider类型为MapProvider<dynamic>。
  • 消费时类型匹配失效:消费时使用Provider.of<MapProvider>等效于Provider.of<MapProvider<dynamic>>,但Provider框架对泛型类型的匹配要求严格,加上隐式类型推断的模糊性,导致无法找到对应的Provider实例。
  • 基本类型正常的原因:当idExtract返回基本类型时,Dart能精准推断出T的具体类型(如int),注册的Provider类型明确为MapProvider<int>,消费时类型完全匹配,因此不会报错。
解决方法

步骤1:创建Provider时显式指定泛型类型

在实例化MapProvider时明确指定泛型参数为ILocationPin,避免类型推断为dynamic,同时可移除不必要的强制类型转换:

return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => MapProvider<ILocationPin>(
            (pin) => pin.id,
          ),
        ),
      ],
      child: MapConsumerWidget()
    )

步骤2:消费Provider时匹配泛型类型

调用Provider.of时,明确指定泛型参数为ILocationPin,保证与注册的Provider类型完全一致:

final mapProvider = Provider.of<MapProvider<ILocationPin>>(context, listen: false);
final providerState = Provider.of<MapProvider<ILocationPin>>(context);
final selectedPin = providerState.selectedLocation;
final locationList = providerState.locationList;

可选优化:使用Consumer组件

推荐使用Provider提供的Consumer组件获取状态,它能更安全地处理泛型类型,同时简化代码:

Consumer<MapProvider<ILocationPin>>(
  builder: (context, mapProvider, child) {
    final selectedPin = mapProvider.selectedLocation;
    final locationList = mapProvider.locationList;
    // 构建UI逻辑
    return ...;
  },
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 03:43:19