yandex / mapkit-android-demo

MapKit Android demo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Проблема с удалением метки (RuntimeException: Failed to remove MapObject)

DemaFay opened this issue · comments

Использую MapView внутри фрагмента.

Версия используемого mapkit 4.3.2-lite
Методы showMarkers и updateMarker вызываются в Main потоке

class MapFragment : BaseFragment(), ClusterListener, ClusterTapListener, MapObjectTapListener, CameraListener {

private var pointsCollection: ClusterizedPlacemarkCollection? = null
private val placemarksOnMap = mutableListOf<PlacemarkMapObject>() //Это список с добавленными маркерами в карту.

//1) В методе onCreate произвожу инициализацию MapKitFactory
  override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          MapKitFactory.initialize(requireContext())
          viewModel = DI.provideViewModel(this)
   }
   
   override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentTaskMapBinding.inflate(inflater, container, false)
        binding.mvMap.map.addCameraListener(this)
        return binding.root
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel.getViewState()
            .observeWith(this) { signal -> //2 тут обрабатываю события. (Показать точки на карте)
                when(signal) {
                    is TaskMapViewModel.ViewSignal.ShowMarkers -> {
                        showMarkers(signal.markers)
                    }
                    is TaskMapViewModel.ViewSignal.UpdateMarker -> { //3 Обновить(Удалить и отобразить снова) точку по его ID
                        updateMarker(signal.marker)
                    }
                }
            }
        viewModel.getCameraState()
            .observeWith(this) { signal ->
                setupCameraPosition(signal.cameraPosition)
            }
        viewModel.onViewCreated()
    }
    
    //4 Тут все работает нормально. Маркеры отображаются на карте.
    private fun showMarkers(markers: List<TaskMarkerData>) {
        binding.mvMap.map.mapObjects.clear() //Очищаю все метки
        placemarksOnMap.clear() //Очищаю список Placemark-ов, которые были добавлены в карту.

        pointsCollection = binding.mvMap.map.mapObjects.addClusterizedPlacemarkCollection(this)
        markers.forEach { marker ->
            placemarksOnMap.add(addMarker(pointsCollection!!, marker)) //Метод addMarker добавляет маркер в карту, при добавлении новой метки создается PlacemarkMapObject которую возвращает метод addMarker и сохраняет его в списке placemarksOnMap
        }
        pointsCollection?.clusterPlacemarks(20.0, Int.MAX_VALUE)
    }
    
    //5 Тут процесс обновления маркера на карте
    private fun updateMarker(marker: TaskMarkerData) {
        placemarksOnMap.find { it.getPointMarker()?.pointId == marker.pointId }?.let { markerToRemove -> //тут мы находим MapObject по ID который был добавлен на карту.
            binding.mvMap.map.mapObjects.remove(markerToRemove) //Тут пытаемся удалить и происходит краш.
            //Так же в интернете был дан немного другой способ для удаления точки.
            //binding.mvMap.map.mapObjects.parent.remove(markerToRemove) //Данный способ так же не работает, в моем случай mapObjects.parent == null
        }
        pointsCollection?.let { points ->
            addMarker(points, marker)
        }
    }
    
    override fun onStart() {
        MapKitFactory.getInstance().onStart()
        binding.mvMap.onStart()
        viewModel.onStart()
        super.onStart()
    }

    override fun onStop() {
        MapKitFactory.getInstance().onStop()
        binding.mvMap.onStop()
        super.onStop()
    }
    
    private fun addMarker(
        pointsCollection: ClusterizedPlacemarkCollection,
        marker: TaskMarkerData
    ): PlacemarkMapObject {
        val bitmap = placemarkBitmapFactory.create(marker)
        val bitmapProvider = ImageProvider.fromBitmap(bitmap)
        val iconStyle = IconStyle()
            .setAnchor(placemarkBitmapFactory.getAnchorPoint(bitmap))
            .setFlat(false)
            .setVisible(true)
        return pointsCollection.addPlacemark(
            marker.location.toPoint(),
            bitmapProvider, iconStyle
        ).also { placemark ->
            placemark.userData = marker
            placemark.addTapListener(this)
            placemark.setupZIndex()
        }
    }

}

Лог с ошибкой:

FATAL EXCEPTION: main
Process: ru.mvideo.lastmile.debug, PID: 27174
 java.lang.RuntimeException: Failed to remove MapObject
Exception stack trace (top 8 entries):
# 0: 7905420  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so 
# 1: 7937112  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so 
# 2: 7936948  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so 
# 3: 7933792  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so 
# 4: 7933592  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so 
# 5: 7936128  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so 
# 6: 13984180  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so 
# 7: 13371316  /data/app/ru.mvideo.lastmile.debug-v9Bf3eSKfLi_T5g_BzEgjA==/base.apk!/lib/arm64-v8a/libmaps-mobile.so Java_com_yandex_mapkit_map_internal_BaseMapObjectCollectionBinding_remove__Lcom_yandex_mapkit_map_MapObject_2

at com.yandex.mapkit.map.internal.BaseMapObjectCollectionBinding.remove(Native Method)
at ru.mvideo.lastmile.ui.screen.tasks.mapv2.TaskMapFragment.updateMarker(TaskMapFragment.kt:147)
at ru.mvideo.lastmile.ui.screen.tasks.mapv2.TaskMapFragment.access$updateMarker(TaskMapFragment.kt:29)
at ru.mvideo.lastmile.ui.screen.tasks.mapv2.TaskMapFragment$onViewCreated$1.invoke(TaskMapFragment.kt:86)
at ru.mvideo.lastmile.ui.screen.tasks.mapv2.TaskMapFragment$onViewCreated$1.invoke(TaskMapFragment.kt:77)
at ru.mvideo.lastmile.util.ui.vm.LiveDataExtensionsKt.observeWith$lambda$0(LiveDataExtensions.kt:13)
at ru.mvideo.lastmile.util.ui.vm.LiveDataExtensionsKt.$r8$lambda$n8EX_c4Nl9gbhRgAGPKyFyQ_NpY(Unknown Source:0)
at ru.mvideo.lastmile.util.ui.vm.LiveDataExtensionsKt$$ExternalSyntheticLambda0.onChanged(Unknown Source:2)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at androidx.lifecycle.LiveData$1.run(LiveData.java:93)
at android.os.Handler.handleCallback(Handler.java:794)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6635)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

Я подробно изучил уже созданные issues связанный с подобной ошибкой RuntimeException: Failed to remove MapObject

Например: #81
В данной ситуации проблема решена object.getParent().remove(object);
В моем случай object.getParent() == null

Так же изучил: #73
cdump commented [on Mar 3, 2019](#73 (comment)
В моем случай вылет происходит вне зависимости вызова метода onDestroy, то есть краш срабатывает всегда, (На этапе работы с приложением родительский фрагмент не закрывается, приложение не сворачивается, не закрывается, и тд.)

Вы добавляете плейсмарки в одну коллекцию, а удаляете их из другой. Это приводит к ошибке.