-
Notifications
You must be signed in to change notification settings - Fork 28.7k
[maps] MissingPluginException when calling methods on maps instance that has been torn down on the native side #43785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[maps] MissingPluginException when calling methods on maps instance that has been torn down on the native side #43785
Comments
Have you tried stopping the app and rebuilding it after adding the dependency? |
Hi Jonathan,
Yes, tried many different solutions:
1 - stopping the app
2 - flutter clean
3 - and others
The problem happen when I try to add multiple markers on the map
dynamically.
I collect the markers position (Lat and Long) from firebase through
StreamBuilder and add it dynamically into the map.
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection("empresas")
.document(_idEmpresa)
.collection("stores")
.snapshots(),
builder: (context, snapshot) {
GoogleMap map = GoogleMap(
mapType: MapType.normal,
scrollGesturesEnabled: true,
initialCameraPosition: _kEmpresa,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
markers: _markers,
);
print(snapshot);
if (snapshot.data == null) return Container();
_loadMarkers(snapshot.data.documents, map);
return Scaffold(
appBar: AppBar(
leading: Icon(Icons.search),
title: _fieldSearch(),
backgroundColor: Colors.green,
actions: <Widget>[],
),
body: map,
floatingActionButton: _floatingActionButtons(map));
//,
});
});
Future<void> _loadMarkers(List dataList, GoogleMap map) async {
_markers.clear();
dataList.forEach((data) async {
Marker marker = Marker(
markerId: MarkerId(data.data.hashCode.toString()),
icon: storeIcon,
infoWindow:
InfoWindow(title: data["Nome"], snippet: data["Tel"]),
position: LatLng(data["Lat"], data["Long"]),
);
_markers.add(marker);
});
}
|
@rafaelsimonassi I probably miss something, but I wonder, why is there |
Hi Stanislav,
The final number varies, sometime it is plugins.flutter.io/google_maps_0
<http://plugins.flutter.io/google_maps_4> or _1.
And yes, it wors when I do not add markers.
Em qua, 30 de out de 2019 às 10:57, Stanislav Bondarenko <
[email protected]> escreveu:
… @rafaelsimonassi <https://github.com/rafaelsimonassi> I probably miss
something, but I wonder, why is there plugins.flutter.io/google_maps_4
not just plugins.flutter.io/google_maps?
Does it work normally when you don't add multiple markers?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#43785?email_source=notifications&email_token=ANBOA2HDIKVNQXFDNKZM6N3QRGHFBA5CNFSM4JGRZ6F2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECUIE5I#issuecomment-547914357>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ANBOA2C6EVDEF36KI66ALC3QRGHFBANCNFSM4JGRZ6FQ>
.
|
I get this too whenever the build function that holds GoogleMap fails. It seems that it causes the map to be removed, and then recreated (with the red error printout). Is there any chance any errors are thrown during build? |
To investigate the issue we would need a minimal runnable reproduction as a single file 👍 |
What to do in this case? I am getting this error |
Same issue. Any solution found?? |
Can you provide us a minimal runnable reproduction as a single file? |
Hmm, I got a lot of error reporting on this too, in my firebase crashlitycs. But the app not crashing... my 133 row:
|
Can you provide us a minimal runnable reproduction as a single file? |
I can't it is a production code. Maybe some bug in the system when I change state. Also maps onCreated is so slow. I am using googlemaps in a pageview. 3 items and animate the pageview index via a timer.periodic 5 seconds. Sometimes oncreate takes 2 seconds to refresh. |
Can you give us exact steps when this happens, so we might be able to reproduce the issue. Also does this happen every time |
You can create a sample dart with stateful widget. A Pageview with 3 googlemaps. The 3 googlemap has a controller and 3 different location. After the map oncreated you just add a marker to it and jump to that marker via camera move or animate. You set a timer.periodic with 5 seconds to animate right the pageview current index and the pageview is infinite. Thats all. In my case the 3 location coming from a firestore/or just a google cloud sql via firebase functions. But not that is the probleme... |
I got new exception: logsNon-fatal Exception: java.lang.Exception: MissingPluginException(No implementation found for method circles#update on channel plugins.flutter.io/google_maps_163)
at MethodChannel.invokeMethod(platform_channel.dart:319)
at GoogleMapController._updateCircles(controller.dart:154)
at _GoogleMapState._updateCircles(google_map.dart:283)
at _GoogleMapState.didUpdateWidget(google_map.dart:245)
at StatefulElement.update(framework.dart:4396)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at RenderObjectElement.updateChildren(framework.dart:5161)
at MultiChildRenderObjectElement.update(framework.dart:5561)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at SliverMultiBoxAdaptorElement.updateChild(sliver.dart:1288)
at SliverMultiBoxAdaptorElement.performRebuild.processElement(sliver.dart:1220)
at SliverMultiBoxAdaptorElement.performRebuild(sliver.dart:1246)
at SliverMultiBoxAdaptorElement.update(sliver.dart:1191)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at RenderObjectElement.updateChildren(framework.dart:5161)
at MultiChildRenderObjectElement.update(framework.dart:5561)
at _ViewportElement.update(viewport.dart:192)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at RenderObjectElement.updateChildren(framework.dart:5161)
at MultiChildRenderObjectElement.update(framework.dart:5561)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at RenderObjectElement.updateChildren(framework.dart:5161)
at MultiChildRenderObjectElement.update(framework.dart:5561)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at RenderObjectElement.updateChildren(framework.dart:5161)
at MultiChildRenderObjectElement.update(framework.dart:5561)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at RenderObjectElement.updateChildren(framework.dart:5161)
at MultiChildRenderObjectElement.update(framework.dart:5561)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatelessElement.update(framework.dart:4298)
at Element.updateChild(framework.dart:2977)
at SingleChildRenderObjectElement.update(framework.dart:5452)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at ProxyElement.update(framework.dart:4557)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at StatefulElement.update(framework.dart:4413)
at Element.updateChild(framework.dart:2977)
at ComponentElement.performRebuild(framework.dart:4243)
at Element.rebuild(framework.dart:3947)
at BuildOwner.buildScope(framework.dart:2432)
at WidgetsBinding.drawFrame(binding.dart:773)
at RendererBinding._handlePersistentFrameCallback(binding.dart:283)
at SchedulerBinding._invokeFrameCallback(binding.dart:1102)
at SchedulerBinding.handleDrawFrame(binding.dart:1041)
at SchedulerBinding._handleDrawFrame(binding.dart:957) |
So basically I got random_numbers: /google_maps_163 /google_maps_55 /google_maps_21 /google_maps_4 with error message |
@klaszlo8207 I think the reason why you get these errors is that the Widget is being rebuilt yet the Controller Completer is already completed once, so the "fresh" Map Widget doesn't have a controller to use. Couple things to try: Cache Map widget. (Aka store the Widget into object and return it instead of re-creating it). |
What I tried: with AutomaticKeepAliveClientMixin and @OverRide on the child of my pageView but with no luck. (the pageView animating to the next page and flashing, and not keep the page state) |
https://github.com/KlausJokinen/plugins/tree/map_keepAlive I haven't had time to create PR yet, but you could give it a try. I've implemented keepAlive option into Google Map Widget. (This branch has some other fixes too from flutter/plugins#2458). |
I tried this:
but I got :
|
@klaszlo8207 en este link sale la respuesta: |
@holaperdedores I tried that before. That was the first thing what I tried... |
|
@KlausJokinen I tried but gave me the same thing. Can you add a sample that is working? Tha sample what I need: 1 PageView with 3 GoogleMaps, the PageView also infinite PageView I do not want flashing, but first time when loaded the map. After it I need to cache, or something |
When you swipe to the different pages the first time it will build the widget, after that it will re-use the "old" one. code sampleimport 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Map Cache Demo',
home: Home(),
);
}
}
class Home extends StatelessWidget {
const Home({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: PageView(
children: <Widget>[
Center(
child: SizedBox(
width: size.width * 0.9,
height: size.height * 0.9,
child: const GoogleMap(
keepAlive: true,
initialCameraPosition: CameraPosition(
target: LatLng(-34, 151),
zoom: 9.4746,
),
),
),
),
Center(
child: SizedBox(
width: size.width * 0.9,
height: size.height * 0.9,
child: const GoogleMap(
keepAlive: true,
initialCameraPosition: CameraPosition(
target: LatLng(40.7128, -74.0060),
zoom: 9.4746,
),
),
),
),
Center(
child: SizedBox(
width: size.width * 0.9,
height: size.height * 0.9,
child: const GoogleMap(
keepAlive: true,
initialCameraPosition: CameraPosition(
target: LatLng(35.652832, 139.839478),
zoom: 9.4746,
),
),
),
),
],
),
);
}
} pubspec.yamlname: map_test
description: Map test.
version: 1.0.0
environment:
sdk: ">=2.2.2 <3.0.0"
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
google_maps_flutter:
git:
url: git://github.com/klausjokinen/plugins/
path: packages/google_maps_flutter
ref: map_keepAlive
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true If you just have a 1 MapWidget which you want to use in 3 different views but load it only once, then what you can do is cache the widget and re-use it. (But with this kind of approach your map configuration must be same in each page). |
This comment was marked as off-topic.
This comment was marked as off-topic.
I was able to reproduce this issue consistently on my local machine by doing the following:
void _onCameraMove(CameraPosition cameraPosition) async {
await Future.delayed(const Duration(seconds: 5));
final cameraLocation = await _mapController?.getScreenCoordinate(cameraPosition.target);
}
This issue seems to appear when accessing the @override
void dispose() {
_mapController?.dispose();
_mapController = null;
super.dispose();
} |
This comment was marked as off-topic.
This comment was marked as off-topic.
The following report has been occurring on both iOS/Android since Flutter 3.24.
In reference to this comment(#153412 (comment)), the error message has just changed due to the switch to Pigeon for method channel communication. I can understand this since this issue(#43785) was originally occurring for Android in our production app. However, what I am wondering is that on iOS, this issue(#43785) was not being reported prior to 3.24, but since 3.24, the above report is being generated. Is iOS reporting a separate issue? flutter doctor -v
|
what is the sollution
|
Minimal (single-file) repro — inspired by @masterwok's comment above: Code
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'GoogleMap Bug Repro',
home: const MainMenuScreen(),
);
}
}
class MainMenuScreen extends StatelessWidget {
const MainMenuScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const MapScreen()),
);
},
child: const Text('Open MapScreen'),
),
),
);
}
}
class MapScreen extends StatefulWidget {
const MapScreen({super.key});
@override
State<MapScreen> createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
GoogleMapController? _controller;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Move map, then go back'),
),
body: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(50.073658, 14.418540),
zoom: 12.0,
),
onMapCreated: (controller) {
_controller = controller;
},
onCameraMove: (position) async {
await Future.delayed(const Duration(seconds: 5));
final controller = _controller!;
// This is where the bug is: we might be accessing controller
// of a map that has already been disposed.
final cameraLocation = await controller.getLatLng(
ScreenCoordinate(x: 0, y: 0),
);
debugPrint('Camera moved to $cameraLocation');
},
),
);
}
} I'm looking into submitting a fix for this.
There are a few ways to achieve this, and a few details I'd like to clarify. Ways to do this:
Future<void> doSomething(...) {
if (_disposed) return;
GoogleMapsFlutterPlatform.instance.doSomething(...);
}
I'd go with option 1 but I don't want to assume anything. A separate question is about what to do in the event of users calling methods on maps that are disposed.
I'd prefer option 2 myself. Option 1 completely breaks the Fail-Fast principle and could lead to developers being suprised that their calls have no effect. Option 3 is the most "correct", imho, but leads to a lot of boilerplate around every method call. Option 2 depends on people using the Dart team's |
I don't think that repro is a case we need to solve at the plugin level; the bug is in the repro code. Clients should not be doing arbitrary delayed interaction with widgets they may themselves be disposing without checks. The problem that should be fixed at the plugin level is the set of cases where the plugin itself does delayed calls to other plugin methods (e.g., callbacks from the native side), which clients of the plugin can't control. |
Ah, sorry, I didn't realize this. From the bug reports above, I got the sense that people get in trouble when inadvertently calling methods on disposed maps. Hence all the talk about PageViews, Firebase callbacks, workarounds involving setting
Do you have an example? I can't find this in the reports and stacktraces above (but it's quite possible I'm looking wrong). Should I be looking at files like |
I thought there were cases of callbacks from native, but looking back maybe it was just artificial delays introduced in callback handlers. However, the initial report appears to be a call from within the plugin, even if not from within a native callback—unless someone manually disposed the controller while the widget still existed, but that seems relatively unlikely. |
I'm a bit lost here. Are you suggesting I focus on the initial report only? That one is from 2019 and the stacktrace has methods |
I'm saying that there are two potential ways of getting this exception:
Any instances of 1 are a valid bug in the plugin, and should be fixed by silently dropping whatever the call is. Any instances of 2 are bugs in the client code. Re-reading, it looks like you want to try to make the experience of 2 better, whereas I was thinking about actually fixing 1. For client code, if we want to make the error more explicit, 3 seems like the best option, except that it would be an |
Thanks for the clarification. Yes, I was referring to the second way to get the exception, since it's what most of the commenters on this thread seem to be reporting. It seems you prefer to address the first way instead? That's valid, of course. It would be helpful to know what you think as a maintainer:
I was referring to try-catch blocks around every call, or some app state that tracks disposal of the controller (since afaik there is no field or getter on the controller to check whether the instance has been disposed). So, for example: final cameraLocation = await controller.getLatLng(screen); becomes if (controllerDisposed) return;
final cameraLocation = await _controller.getLatLng(screen); Admittedly not a lot of boilerplate in this case, but in more complex cases where we can't just return, it could mean more code than that. |
There's no scenario where clients should be writing try/catch to handle calling into a disposed object; they should not be making the call in the first place. We would not throw exceptions intentionally, because it's a programming error.
I'm not sure I follow. The only way to call a disposed controller would be to have a long-lived controller reference. Why would the client solution not be to simply null out that reference when the controller is disposed? I don't see why additional state would be required. |
If we don't actually have any instances of current errors within the plugin, we can treat this as just covering improving the client error. I may have just misread a stack during triage and thought we did have a plugin error somewhere. |
You're right. I thought maybe the client might want to distinguish between controller being |
@stuartmorgan-g Looking back at the stack trace for the original issue, it stems from a
Each of these methods follow this pattern
Each time there is awaiting for the There should be a I have tested and verified that this is the problem by adding logging to For me this error occurs very often on the web version of our Flutter app as it is easy to switch pages while the map is still initializing. I'm just added a PR now to address this - #9227 |
This is the one of the exceptions caused when the controller has been disposed when calling
This is the other exception which I observed where the controller is looked up after the
|
Was this link perhaps garbled? It links to an issue that seems unrelated at first glance. |
I've fixed up the link as the PR is in the packages repository |
Uh oh!
There was an error while loading. Please reload this page.
Hello, I am experiencing this error below, whenever I use the google map.
Also, please find below the flutter doctor -v output as well.
The text was updated successfully, but these errors were encountered: