Flutter中Place列表无法打印展示及Provider相关问题求助
解决Flutter中Place列表无法展示的问题
问题详情
调试确认数据已成功映射为Place列表,但界面始终显示加载指示器。添加return语句后,出现新错误:找不到此Consumer<List
原界面代码
class MapScreen extends StatelessWidget { const MapScreen({super.key}); @override Widget build(BuildContext context) { return MultiProvider( providers: [ FutureProvider( create: (context) => GeolocatorService().getLocation(), initialData: null, ), ProxyProvider<Position, Future<List<Place>>>( update: (context, position, places) { return PlacesService() .getPlaces(position.latitude, position.longitude); }, ) ], child: const MaterialApp( home: GetScreen(), ), ); } } class GetScreen extends StatelessWidget { const GetScreen({super.key}); @override Widget build(BuildContext context) { final currentPosition = Provider.of<Position?>(context); if (currentPosition != null) { final placeService = Provider.of<Future<List<Place>>>(context); FutureProvider( create: (context) => placeService, initialData: const [], child: 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<List<Place>>( builder: (context, places, child) { 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, ), ), ); })) ], ); }, )), ); } 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: const Center(child: CircularProgressIndicator())); } }
数据获取与映射代码
class PlacesService { final key = 'AIzaSyDM32Kzq-Pz_MPorUAYxWgDX7qb3nt2S6M'; Future<List<Place>> getPlaces(double lat, double lng) async { var response = await http.get(Uri.parse( 'https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=$lat,$lng&type=restaurant&rankby=distance&key=$key ')); var json = convert.jsonDecode(response.body); var jsonResults = json['results'] as List; return jsonResults.map((place) => Place.fromJson(place)).toList(); } } class Place { final Geometry geometry; final String name; final double rating; final int userRatingCount; final String vicinity; Place(this.geometry, this.name, this.rating, this.userRatingCount, this.vicinity); Place.fromJson(Map<dynamic, dynamic> parsedJson) : geometry = Geometry.fromJson(parsedJson['geometry']), name = parsedJson['name'], rating = (parsedJson['rating'] != null) ? (parsedJson['rating'])!.toDouble() : 0.0, userRatingCount = (parsedJson['user_ratings_total'] != null) ? parsedJson['user_ratings_total'] : 0, vicinity = parsedJson['vicinity']; }
问题原因与修复方案
1. 未返回核心Widget(初始加载问题)
在GetScreen的build方法中,当currentPosition != null时,创建了FutureProvider但未return该Widget,导致代码直接走到最后返回加载界面,这是界面一直显示CircularProgressIndicator的根本原因。
2. Provider层级与监听错误(添加return后的新问题)
当前Provider提供的是Future<List<Place>>,但你试图用Consumer<List<Place>>直接监听List,嵌套FutureProvider的方式会导致层级混乱,无法被正确识别。
推荐使用FutureBuilder替代嵌套Provider,直接处理异步状态:
修改后的GetScreen代码:
class GetScreen extends StatelessWidget { const GetScreen({super.key}); @override Widget build(BuildContext context) { final currentPosition = Provider.of<Position?>(context); if (currentPosition != null) { final futurePlaces = Provider.of<Future<List<Place>>>(context); // 此处添加return返回核心界面 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: FutureBuilder<List<Place>>( future: futurePlaces, builder: (context, snapshot) { // 根据异步状态处理UI if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('未找到餐厅')); } else { 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), ), ); })) ], ); } }, ), ); } 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: const Center(child: CircularProgressIndicator())); } }
额外优化建议
- 避免在
build方法中直接创建PlacesService()实例,可通过Provider注入,提升代码可测试性。 - 检查Google Places API的请求URL末尾是否有多余空格(原代码中key后有空格),可能导致请求失败。
内容的提问来源于stack exchange,提问作者Trung Phạm
相关产品推荐
相关产品推荐

