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

Flutter中MapScreen组件找不到Provider<Position> 求助

问题分析与修复方案

核心问题

你遇到的ProviderNotFoundException本质是上下文层级错误:你在_MapScreenState的context(对应MapScreen组件的上下文)中调用Provider.of<Position>(context),但这个上下文位于你创建的MultiProvider之上,无法访问到MultiProvider内部提供的Position实例。此外代码里还有几处Provider配置错误,进一步加剧了问题。

具体修复步骤

1. 修正FutureProvider的初始值

FutureProvider的initialData需要传入对应类型的同步值,而不是Future对象。你原来写的initialData: locatorService.getLocation()返回的是Future<Position>,和FutureProvider要求的Position?类型不匹配,改成:

FutureProvider<Position?>(
  create: (context) => locatorService.getLocation(),
  initialData: null, // 用null作为初始值,或者传入一个默认Position实例
)

2. 使用子上下文读取Provider

不要直接用State的context去读取MultiProvider内部的Provider,而是在MultiProvider的子树中使用新的上下文。可以通过Builder组件或者将逻辑内联到MaterialApp的home属性中,确保读取Provider的上下文处于MultiProvider之下。

3. 修复ProxyProvider的空安全逻辑

当position为null时,直接调用position!会触发空指针异常,需要先做null判断:

ProxyProvider<Position?, Future<List<Place>>>(
  update: (context, position, previousPlaces) {
    if (position == null) {
      return Future.value([]); // 位置为空时返回空列表
    }
    return placesService.getPlaces(position.latitude, position.longitude);
  },
)

4. 简化嵌套的FutureProvider

你在原代码里嵌套的FutureProvider是冗余的,直接用FutureBuilder处理Future<List<Place>>即可,不需要额外包装。

修改后的完整代码

class MapScreen extends StatefulWidget {
  const MapScreen({Key? key}) : super(key: key);

  @override
  State<MapScreen> createState() => _MapScreenState();
}

final locatorService = GeolocatorService();
final placesService = PlacesService();

class _MapScreenState extends State<MapScreen> {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        FutureProvider<Position?>(
          create: (context) => locatorService.getLocation(),
          initialData: null,
        ),
        ProxyProvider<Position?, Future<List<Place>>>(
          update: (context, position, previousPlaces) {
            if (position == null) {
              return Future.value([]);
            }
            return placesService.getPlaces(position.latitude, position.longitude);
          },
        )
      ],
      child: MaterialApp(
        home: Builder( // 使用Builder获取MultiProvider子树的上下文
          builder: (innerContext) {
            return Scaffold(
              appBar: AppBar(
                leading: IconButton(
                    onPressed: () {
                      Navigator.pop(context);
                    },
                    icon: const Icon(Icons.arrow_back_ios_new_rounded)),
                title: const Text('Tìm nhà hàng'),
                elevation: 0,
                backgroundColor: Colors.purple,
                centerTitle: true,
              ),
              body: Consumer<Position?>(
                builder: (context, currentPosition, child) {
                  if (currentPosition == null) {
                    return const Center(child: CircularProgressIndicator());
                  }
                  return Consumer<Future<List<Place>>>(
                    builder: (context, placesFuture, child) {
                      return FutureBuilder<List<Place>>(
                        future: placesFuture,
                        initialData: const [],
                        builder: (context, snapshot) {
                          if (snapshot.connectionState == ConnectionState.waiting) {
                            return const Center(child: CircularProgressIndicator());
                          }
                          final places = snapshot.data ?? [];
                          return Column(
                            children: <Widget>[
                              SizedBox(
                                height: MediaQuery.of(context).size.height / 3,
                                width: MediaQuery.of(context).size.width,
                                child: GoogleMap(
                                  initialCameraPosition: CameraPosition(
                                      target: LatLng(currentPosition.latitude,
                                          currentPosition.longitude),
                                      zoom: 16.0),
                                  zoomGesturesEnabled: true,
                                ),
                              ),
                              const SizedBox(height: 10.0),
                              Expanded(
                                child: ListView.builder(
                                  itemCount: places.length,
                                  itemBuilder: (context, index) {
                                    return Card(
                                      child: ListTile(
                                        title: Text(places[index].name),
                                      ),
                                    );
                                  },
                                ),
                              )
                            ],
                          );
                        },
                      );
                    },
                  );
                },
              ),
            );
          },
        ),
      ),
    );
  }
}

关键改动说明

  • 用Builder获取MultiProvider子树的上下文,确保能正确读取内部的Provider实例
  • 替换了错误的FutureProvider初始值
  • 增加了position为null时的安全处理
  • 用FutureBuilder直接处理Future<List<Place>>,去掉冗余的FutureProvider嵌套

内容的提问来源于stack exchange,提问作者Trung Phạm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:57:40