osm_flutter icon indicating copy to clipboard operation
osm_flutter copied to clipboard

ClassCastException and PlatformException

Open gcsaba2 opened this issue 3 years ago • 8 comments

Looks similar to issue #115

I've upgraded from 0.26.0-rc.2 to 0.26.1

I'm running from Android Studio in debug mode, I've connected a mobile phone with Android 10. The map sometimes crashes completely (killing the app) and sometimes it's stable but a lot of error messages are printed.

It worked without issues on 0.26.0-rc.2. It is possible that this issue only happens in debug mode, I didn't try deploying a production apk to the phone.

I did flutter clean and I also deleted the local flutter cache.

Is there anything I can do to help? Can I enable additional debug logging somehow?

E/DRM/DcfDecoder(20709): decodeDrmImageIfNeeded stream caught ClassCastException

E/flutter (20709): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: PlatformException(404, Attempt to invoke virtual method 'org.osmdroid.views.MapViewRepository org.osmdroid.views.MapView.getRepository()' on a null object reference, java.lang.NullPointerException: Attempt to invoke virtual method 'org.osmdroid.views.MapViewRepository org.osmdroid.views.MapView.getRepository()' on a null object reference
E/flutter (20709): 	at org.osmdroid.views.overlay.infowindow.InfoWindow.<init>(InfoWindow.java:53)
E/flutter (20709): 	at org.osmdroid.views.overlay.infowindow.BasicInfoWindow.<init>(BasicInfoWindow.java:54)
E/flutter (20709): 	at org.osmdroid.views.overlay.infowindow.MarkerInfoWindow.<init>(MarkerInfoWindow.java:41)
E/flutter (20709): 	at org.osmdroid.views.MapViewRepository.getDefaultMarkerInfoWindow(MapViewRepository.java:55)
E/flutter (20709): 	at org.osmdroid.views.overlay.Marker.<init>(Marker.java:116)
E/flutter (20709): 	at org.osmdroid.views.overlay.Marker.<init>(Marker.java:93)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterMarker.<init>(FlutterMaker.kt:22)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterMarker.<init>(FlutterMaker.kt:55)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.createMarker(FlutterOsmView.kt:691)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.createMarker$default(FlutterOsmView.kt:690)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.addMarker(FlutterOsmView.kt:622)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.addMarker$default(FlutterOsmView.kt:611)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.addMarkerManually(FlutterOsmView.kt:826)
E/flutter (20709): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.onMethodCall(FlutterOsmView.kt:456)
E/flutter (20709): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/flutter (20709): 	at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:84)
E/flutter (20709): 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:865)
E/flutter (20709): 	at android.os.MessageQueue.nativePollOnce(Native Method)
E/flutter (20709): 	at android.os.MessageQueue.next(MessageQueue.java:336)
E/flutter (20709): 	at android.os.Looper.loop(Looper.java:174)
E/flutter (20709): 	at android.app.ActivityThread.main(ActivityThread.java:7386)
E/flutter (20709): 	at java.lang.reflect.Method.invoke(Native Method)
E/flutter (20709): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/flutter (20709): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
E/flutter (20709): , null)
E/flutter (20709): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:607:7)
E/flutter (20709): #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:18)
E/flutter (20709): <asynchronous suspension>
E/flutter (20709): #2      MethodChannelOSM.addMarker (package:flutter_osm_interface/src/channel/osm_method_channel.dart:598:5)
E/flutter (20709): <asynchronous suspension>
E/flutter (20709): #3      MobileOSMController.addMarker.<anonymous closure> (package:flutter_osm_plugin/src/controller/osm/osm_controller.dart:443:9)
E/flutter (20709): <asynchronous suspension>
E/flutter (20709): #4      MobileOSMController.addMarker (package:flutter_osm_plugin/src/controller/osm/osm_controller.dart:442:7)
E/flutter (20709): <asynchronous suspension>
E/flutter (20709): #5      MapController.addMarker (package:flutter_osm_plugin/src/controller/map_controller.dart:273:5)
E/flutter (20709): <asynchronous suspension>
E/flutter (20709): #6      _MapPanelState._updateUserMarkerOnTheMap (package:nyomtass_te_is/screens/map/map_panel.dart:253:9)
E/flutter (20709): <asynchronous suspension>
E/flutter (20709): 

gcsaba2 avatar Dec 10 '21 18:12 gcsaba2

can you provide scenario of that crash and part of your code ? because the lasts version 0.20+ doesn't support setState if you have it try to replace it with ValueNotifier or makethe map in parent widget separate from widget that show the information

liodali avatar Dec 10 '21 19:12 liodali

you code crash in this method _updateUserMarkerOnTheMap can you share it

liodali avatar Dec 10 '21 19:12 liodali

Below is the sanitized version of the code. Let me know if you need the whole code (it might be difficult to read).

I have a Timer which calls the _updateUserMarkerOnTheMap() every 5 seconds. This method gets the current GPS position (based on the "location" package) and updates the marker on the map. The location of the marker is stored in the _lastLocation field. I can change this to a ValueNotifier if you think that will help.

// field inside the State object
LocationData? _lastLocation; // last place where this person was

// start a thread which updates the user's location every x seconds
      onMapIsReady: (ready) {
        if (_locationUpdater == null) {
          developer.log("Starting location updater thread.");
          _updateUserMarkerOnTheMap();  // update the first time
          _locationUpdater = Timer.periodic(
            Duration(seconds: settings.locationRefreshSec), _updateUserMarkerOnTheMap);
        }
      }
      
// this is the method which is invoked

  Future<void> _updateUserMarkerOnTheMap([Timer? timer]) async {
    var location = await _getCurrentLocation();  // GPS location from 'location' package
    if (location != null) {
        developer.log("Setting new location marker.");
        if (_lastLocation != null) {
          // remove previous marker so it looks like the person is moving
          await _mapController.removeMarker(GeoPoint(
              latitude: _lastLocation!.latitude!,
              longitude: _lastLocation!.longitude!
          ));
        } else {
          await _mapController.goToLocation(GeoPoint(
              latitude: location.latitude ?? 47.487016,
              longitude: location.longitude ?? 19.057167));
          await _mapController.setZoom(zoomLevel: 17);
        }
        // draw new marker
        await _mapController.addMarker(GeoPoint(    // this is line 253 from the stack trace
            latitude: location.latitude ?? 47.487016,
            longitude: location.longitude ?? 19.057167),
            markerIcon: _osmMap.userLocationMarker?.personMarker
        );

        // set new location
        _lastLocation = location;
        final settings = context.read<Settings>();
        if (_lastLocation != null && _lastLocation!.latitude != null && _lastLocation!.longitude != null) {
          settings.updateLastLocation(_lastLocation!.latitude, _lastLocation!.longitude);
        }
      
    }
  }

gcsaba2 avatar Dec 10 '21 20:12 gcsaba2

why you didn't use

 await controller.currentLocation();
 await controller.enableTracking();

you can listen to current location with callback in OSMFlutter onLocationChanged i will add in the future some parameter to customizable get current user location

liodali avatar Dec 10 '21 21:12 liodali

put _lastLocation in ValueNotifier because it make widget rebuild when that value change or like i told you separate map widget from widget that responsible to show data i will give later small example how to do it

liodali avatar Dec 11 '21 09:12 liodali

Thank you @liodali I'll give it a try and let you know the results.

gcsaba2 avatar Dec 11 '21 10:12 gcsaba2

Moving the value into a ValueNotifier seems to have fixed the issue, thank you for your help.

I see another stack trace in the logs. It doesn't cause any errors, the marker is added correctly.

E/null    (20407): java.lang.NullPointerException: Attempt to invoke virtual method 'org.osmdroid.views.MapViewRepository org.osmdroid.views.MapView.getRepository()' on a null object reference
E/null    (20407): 	at org.osmdroid.views.overlay.infowindow.InfoWindow.<init>(InfoWindow.java:53)
E/null    (20407): 	at org.osmdroid.views.overlay.infowindow.BasicInfoWindow.<init>(BasicInfoWindow.java:54)
E/null    (20407): 	at org.osmdroid.views.overlay.infowindow.MarkerInfoWindow.<init>(MarkerInfoWindow.java:41)
E/null    (20407): 	at org.osmdroid.views.MapViewRepository.getDefaultMarkerInfoWindow(MapViewRepository.java:55)
E/null    (20407): 	at org.osmdroid.views.overlay.Marker.<init>(Marker.java:116)
E/null    (20407): 	at org.osmdroid.views.overlay.Marker.<init>(Marker.java:93)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterMarker.<init>(FlutterMaker.kt:22)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterMarker.<init>(FlutterMaker.kt:55)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.createMarker(FlutterOsmView.kt:691)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.createMarker$default(FlutterOsmView.kt:690)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.addMarker(FlutterOsmView.kt:622)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.addMarker$default(FlutterOsmView.kt:611)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.addMarkerManually(FlutterOsmView.kt:826)
E/null    (20407): 	at hamza.dali.flutter_osm_plugin.FlutterOsmView.onMethodCall(FlutterOsmView.kt:456)
E/null    (20407): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/null    (20407): 	at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:84)
E/null    (20407): 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:865)
E/null    (20407): 	at android.os.MessageQueue.nativePollOnce(Native Method)
E/null    (20407): 	at android.os.MessageQueue.next(MessageQueue.java:336)
E/null    (20407): 	at android.os.Looper.loop(Looper.java:174)
E/null    (20407): 	at android.app.ActivityThread.main(ActivityThread.java:7386)
E/null    (20407): 	at java.lang.reflect.Method.invoke(Native Method)
E/null    (20407): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/null    (20407): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
D/BufferQueueProducer(20407): [SurfaceTexture-0-20407-2](this:0x7bb1af9800,id:2,api:1,p:606,c:20407) cancelBuffer: slot 0
D/BufferQueueProducer(20407): [SurfaceTexture-0-20407-2](this:0x7bb1af9800,id:2,api:1,p:606,c:20407) cancelBuffer: slot 0
D/Surface (20407): Surface::connect(this=0x7b849cf000,api=1)
D/Surface (20407): Surface::setBufferCount(this=0x7b849cf000,bufferCount=3)
D/Surface (20407): Surface::allocateBuffers(this=0x7b849cf000)

As I see it, in FlutterOsmView.kt we create a new FlutterMarker: https://github.com/liodali/osm_flutter/blob/ed7a9ea23da80b16a9148695ee5f03aa73773f1e/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/FlutterOsmView.kt#L691

val marker = FlutterMarker(context, map!!, geoPoint)

and then this calls the FlutterMarker constructor: https://github.com/liodali/osm_flutter/blob/0ff439b10e99e67d2941641cc5ab3b0b43592135/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/FlutterMaker.kt#L22

which then calls the InfoWindow constructor: https://github.com/osmdroid/osmdroid/blob/master/osmdroid-android/src/main/java/org/osmdroid/views/overlay/infowindow/InfoWindow.java#L53

which has this:

mMapView.getRepository().add(this);

It looks like the map!! passed in FlutterOsmView is null and this causes a NPE. I checked the code of FlutterOsmView and see this:

    private fun initMap() {
        map = mapView

but I don't see how is mapView set, so I don't understand why it was null.

gcsaba2 avatar Dec 12 '21 09:12 gcsaba2

i will make more investigation why that's happen, but what i know for now, that problem because map is reload it and we have another call use previous context of the map i will improve that,

liodali avatar Dec 12 '21 12:12 liodali