尝试使用 google 地图时,查找已停用的小部件的祖先是不安全的
Looking up a deactivated widget's ancestor is unsafe when try use google map
第一次运行时,当我返回时出现此错误,请帮助。我无法解决这个问题。我尝试在我的应用程序中使用地图。谁能帮我?状态管理呢?尝试将地图集成到应用程序
我想知道为什么会出现这种情况并且应用程序出现错误?使用最新版本的 flutter.
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
...
你不能在dispose()
里面调用Provider.of(context)
,因为Flutter不能保证调用dispose()
时上下文在树中的正确位置。
相反,您可以:
- 在
initState()
中调用 Provider.of(context)
- 将其存储在
State
class 上的一个字段中
- 使用
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.
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
...
你不能在dispose()
里面调用Provider.of(context)
,因为Flutter不能保证调用dispose()
时上下文在树中的正确位置。
相反,您可以:
- 在
initState()
中调用 - 将其存储在
State
class 上的一个字段中
- 使用
dispose()
中的字段
Provider.of(context)
例如:
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();
}
}