Flutter地震查询应用报错:The method 'Cast' was called on null及资源问题
解决Flutter地震查询应用的两个关键错误:Cast调用空值与资源释放失败
一、修复"The method 'Cast' was called on null"错误
问题根源
EarthquakeModel.fromJson方法中,直接对json['bbox']调用cast<double>(),但当JSON数据中不存在bbox字段或其值为null时,json['bbox']返回null,此时调用cast方法会触发空值调用错误。
修复代码
给bbox的解析逻辑添加空值判断,仅当字段存在且非空时执行类型转换:
class EarthquakeModel { String? type; Metadata? metadata; List<Features>? features; List<double>? bbox; EarthquakeModel({this.type, this.metadata, this.features, this.bbox}); EarthquakeModel.fromJson(Map<String, dynamic> json) { type = json['type']; metadata = json['metadata'] != null ? new Metadata.fromJson(json['metadata']) : null; if (json['features'] != null) { features = <Features>[]; json['features'].forEach((v) { features!.add(new Features.fromJson(v)); }); } // 新增空值判断,避免null调用cast bbox = json['bbox'] != null ? json['bbox'].cast<double>() : null; } }
二、修复"a resource failed to call release error"错误
问题根源
- 状态隔离混乱:主页面与
BuildGoogleMap组件各自维护独立的Marker列表和Map控制器实例,导致资源无法同步释放,控制器重复创建引发冲突。 - 嵌套setState滥用:FloatingActionButton点击事件中嵌套两层
setState,触发不必要的重复刷新,干扰资源生命周期管理。 - 无状态组件误用:
BuildGoogleMap无需维护自身状态,却使用有状态组件,增加了资源管理复杂度。
修复方案
1. 将地图组件改为无状态组件,通过外部参数传递依赖
class BuildGoogleMap extends StatelessWidget { final Completer<GoogleMapController> controller; final Set<Marker> markers; const BuildGoogleMap({Key? key, required this.controller, required this.markers}) : super(key: key); @override Widget build(BuildContext context) { return Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: GoogleMap( initialCameraPosition: const CameraPosition( target: LatLng(36.1083333, 117.8608333), zoom: 3 ), mapType: MapType.normal, onMapCreated: (GoogleMapController controller){ this.controller.complete(controller); }, markers: markers, ), ); } }
2. 优化主页面状态管理与事件逻辑
- 移除嵌套
setState,在Future回调内统一触发状态刷新 - 共享Map控制器和Marker列表给地图组件,确保资源统一管理
class QuakeApp extends StatefulWidget { const QuakeApp({Key? key}) : super(key: key); @override State<QuakeApp> createState() => _QuakeAppState(); } class _QuakeAppState extends State<QuakeApp> { late Future<EarthquakeModel> quakeData; final Completer<GoogleMapController> _controller = Completer(); final List<Marker> _markerList = <Marker>[]; @override void initState() { super.initState(); quakeData = Network().getEarthquake(); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ BuildGoogleMap(controller: _controller, markers: Set<Marker>.of(_markerList)), ], ), floatingActionButton: FloatingActionButton.extended( onPressed: (){ _markerList.clear(); quakeData.then((quake) { quake.features?.forEach((element) { _markerList.add(Marker( markerId: MarkerId(element.id ?? ''), infoWindow: InfoWindow( title: element.properties?.mag?.toString(), ), icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueMagenta), position: LatLng(element.geometry?.coordinates?[1] ?? 0, element.geometry?.coordinates?[0] ?? 0), onTap: (){} )); }); // 统一在数据加载完成后刷新状态 setState(() {}); }); }, label: const Text('Find Quakes') ), ); } }
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

