尝试使用谷歌地图时查找已停用小部件的祖先是不安全的
Posted
技术标签:
【中文标题】尝试使用谷歌地图时查找已停用小部件的祖先是不安全的【英文标题】:Looking up a deactivated widget's ancestor is unsafe when try use google map 【发布时间】:2021-09-27 03:44:33 【问题描述】:第一次工作,然后当我回去我得到这个错误,请帮助。我无法解决这个问题。我尝试在我的应用程序中使用地图。谁能帮我?状态管理呢?尝试将地图集成到应用中
我想知道为什么发生这种情况并且应用程序出现错误?最新版本的颤振使用。
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:medicine/models/geometry.dart';
import 'package:medicine/models/location.dart';
import 'package:medicine/models/place.dart';
import 'package:medicine/models/place_search.dart';
import 'package:medicine/services/geolocator_service.dart';
import 'package:medicine/services/marker_service.dart';
import 'package:medicine/services/places_service.dart';
class ApplicationBloc with ChangeNotifier
final geoLocatorService = GeolocatorService();
final placesService = PlacesService();
final markerService = MarkerService();
//Variables
Position? currentLocation;
List<PlaceSearch>? searchResults;
StreamController<Place?> selectedLocation = StreamController<Place?>();
StreamController<LatLngBounds> bounds = StreamController<LatLngBounds>();
Place? selectedLocationStatic;
String? placeType;
List<Place>? placeResults;
List<Marker> markers = [];
ApplicationBloc()
setCurrentLocation();
setCurrentLocation() async
currentLocation = await geoLocatorService.getCurrentLocation();
selectedLocationStatic = Place(
name: null,
geometry: Geometry(
location: Location(
lat: currentLocation!.latitude, lng: currentLocation!.longitude),
),
);
notifyListeners();
searchPlaces(String searchTerm) async
searchResults = await placesService.getAutocomplete(searchTerm);
notifyListeners();
setSelectedLocation(String placeId) async
var sLocation = await placesService.getPlace(placeId);
selectedLocation.add(sLocation);
selectedLocationStatic = sLocation;
searchResults = null;
notifyListeners();
clearSelectedLocation()
selectedLocation.add(null);
selectedLocationStatic = null;
searchResults = null;
placeType = null;
notifyListeners();
togglePlaceType(String value, bool selected) async
if (selected)
placeType = value;
else
placeType = null;
if (placeType != null)
var places = await placesService.getPlaces(
selectedLocationStatic!.geometry.location.lat,
selectedLocationStatic!.geometry.location.lng,
placeType!);
markers = [];
if (places.length > 0)
var newMarker = markerService.createMarkerFromPlace(places[0], false);
markers.add(newMarker);
var locationMarker =
markerService.createMarkerFromPlace(selectedLocationStatic!, true);
markers.add(locationMarker);
var _bounds = markerService.bounds(Set<Marker>.of(markers));
bounds.add(_bounds!);
notifyListeners();
@override
void dispose()
selectedLocation.close();
bounds.close();
super.dispose();
这是map_screen.dart是
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:medicine/blocs/application_bloc.dart';
import 'package:medicine/models/place.dart';
import 'package:provider/provider.dart';
class MapScreen extends StatefulWidget
MapScreen(
Key? key,
) : super(key: key);
@override
_MapScreenState createState() => _MapScreenState();
class _MapScreenState extends State<MapScreen>
Completer<GoogleMapController> _mapController = Completer();
late StreamSubscription locationSubscription;
late StreamSubscription boundsSubscription;
final _locationController = TextEditingController();
@override
void initState()
final applicationBloc =
Provider.of<ApplicationBloc>(context, listen: false);
//Listen for selected Location
locationSubscription =
applicationBloc.selectedLocation.stream.listen((place)
if (place != null)
_locationController.text = place.name ?? "";
_goToPlace(place);
else
_locationController.text = "";
);
applicationBloc.bounds.stream.listen((bounds) async
final GoogleMapController controller = await _mapController.future;
controller.animateCamera(CameraUpdate.newLatLngBounds(bounds, 50));
);
super.initState();
@override
void dispose()
final applicationBloc =
Provider.of<ApplicationBloc>(context, listen: false);
applicationBloc.dispose();
_locationController.dispose();
locationSubscription.cancel();
boundsSubscription.cancel();
super.dispose();
@override
Widget build(BuildContext context)
final applicationBloc = Provider.of<ApplicationBloc>(context);
return Scaffold(
appBar: AppBar(
title: Text('Map'),
),
body: (applicationBloc.currentLocation == null)
? Center(
child: CircularProgressIndicator(),
)
: ListView(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _locationController,
textCapitalization: TextCapitalization.words,
decoration: InputDecoration(
hintText: 'Search by City',
suffixIcon: Icon(Icons.search),
),
onChanged: (value) => applicationBloc.searchPlaces(value),
onTap: () => applicationBloc.clearSelectedLocation(),
),
),
Stack(
children: [
Container(
height: 300.0,
child: GoogleMap(
mapType: MapType.normal,
myLocationEnabled: true,
initialCameraPosition: CameraPosition(
target: LatLng(
applicationBloc.currentLocation!.latitude,
applicationBloc.currentLocation!.longitude),
zoom: 14,
),
onMapCreated: (GoogleMapController controller)
_mapController.complete(controller);
,
markers: Set<Marker>.of(applicationBloc.markers),
),
),
if (applicationBloc.searchResults != null &&
applicationBloc.searchResults!.length != 0)
Container(
height: 300.0,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.black.withOpacity(.6),
backgroundBlendMode: BlendMode.darken)),
if (applicationBloc.searchResults != null)
Container(
height: 300.0,
child: ListView.builder(
itemCount: applicationBloc.searchResults!.length,
itemBuilder: (context, index)
return ListTile(
title: Text(
applicationBloc
.searchResults![index].description,
style: TextStyle(color: Colors.white),
),
onTap: ()
applicationBloc.setSelectedLocation(
applicationBloc
.searchResults![index].placeId);
,
);
),
),
],
),
SizedBox(
height: 20.0,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Find Nearest',
style: TextStyle(
fontSize: 25.0, fontWeight: FontWeight.bold)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
spacing: 8.0,
children: [
FilterChip(
label: Text('Pharmacy'),
onSelected: (val) => applicationBloc
.togglePlaceType('pharmacy', val),
selected: applicationBloc.placeType == 'pharmacy',
selectedColor: Colors.blue),
],
),
)
],
));
Future<void> _goToPlace(Place place) async
final GoogleMapController controller = await _mapController.future;
controller.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(
place.geometry.location.lat, place.geometry.location.lng),
zoom: 14.0),
),
);
错误是
The following assertion was thrown while finalizing the widget tree:
Looking up a deactivated widget's ancestor is unsafe.
At this point, the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
When the exception was thrown, this was the stack
#0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure>
package:flutter/…/widgets/framework.dart:3944
#1 Element._debugCheckStateIsActiveForAncestorLookup
package:flutter/…/widgets/framework.dart:3958
#2 Element.getElementForInheritedWidgetOfExactType
package:flutter/…/widgets/framework.dart:3984
#3 Provider._inheritedElementOf
package:provider/src/provider.dart:327
#4 Provider.of
package:provider/src/provider.dart:284
...
【问题讨论】:
【参考方案1】:你不能在dispose()
内部调用Provider.of(context)
,因为当dispose()
被调用时,Flutter 不能保证上下文在树中的正确位置。
相反,您可以:
-
在
initState()
中致电Provider.of(context)
将其存储在 State
类的字段中
使用dispose()
中的字段
例如:
class _MapScreenState extends State<MapScreen>
late final ApplicationBloc applicationBloc;
@override
void initState()
super.initState();
// ... other logic
applicationBloc = Provider.of<ApplicationBloc>(context, listen: false);
// build, etc
@override
void dispose()
applicationBloc.dispose();
// other logic...
super.dispose();
【讨论】:
以上是关于尝试使用谷歌地图时查找已停用小部件的祖先是不安全的的主要内容,如果未能解决你的问题,请参考以下文章
如果添加到动画列表,Flutter 查找已停用小部件的祖先是不安全的