IllegalArgumentException: Unmanaged descriptor using gms.maps.model.Marker.setIcon

谁说我不能喝 提交于 2019-11-28 21:02:51

When clearing the map with

    googleMap.clear();

**remove any reference to all the markers** on the map. I had the problem and figured out that the problem was with my code which I forgot to remove reference to a marker and tried to change icon of a cleared Marker

I was too getting same exception and setting silent exception with try/catch would not have been solution as user is not able to see current location in my case:

java.lang.IllegalArgumentException: Unmanaged descriptor at com.google.maps.api.android.lib6.common.k.b(:com.google.android.gms.DynamiteModulesB:162) at com.google.maps.api.android.lib6.impl.o.c(:com.google.android.gms.DynamiteModulesB:75) at com.google.maps.api.android.lib6.impl.db.a(:com.google.android.gms.DynamiteModulesB:334) at com.google.android.gms.maps.model.internal.q.onTransact(:com.google.android.gms.DynamiteModulesB:204) at android.os.Binder.transact(Binder.java:361) at com.google.android.gms.maps.model.internal.zzf$zza$zza.zzL(Unknown Source) at com.google.android.gms.maps.model.Marker.setIcon(Unknown Source)

What I was doing :

Minimize the map fragment screen by pressing home button and then starting app from launcher.

What code was doing:

Checking is marker is not null and location is not null set location and icon.

     if (markerCurrentLocation == null && googleMap != null) {
            markerCurrentLocation = googleMap.addMarker(new MarkerOptions()
                    .position(new LatLng(0.0, 0.0))
                    .icon(null));
            markerCurrentLocation.setTag(-101);
       }

         if (markerCurrentLocation != null && location != null) {
                markerCurrentLocation.setPosition(new LatLng(location.getLatitude(), location.getLongitude()));
                if (ORDER_STARTED) {
                   markerCurrentLocation.setIcon(CURRENT_MARKER_ORANGE);
                } else {
                    markerCurrentLocation.setIcon(CURRENT_MARKER_GRAY);
                }       
         }

Exception was at : markerCurrentLocation.setIcon();

How I got rid of this exception:

I removed the following line

 if (markerCurrentLocation == null && googleMap != null) 

Which means I am initializing marker again. If you encounter this error, try not to setIcon() on old marker, instead inflate new marker and then use setIcon().

Explanation:

I ASSUME (not sure) exception reason was if code is trying to setIcon() again on marker on which it is already set , at particular instance like in my case Map is resuming or may be in your case marker goes out of visible part of map and comes in or something similar.

For sure there is no problem with descriptor we get from method BitmapDescriptorFactory.fromBitmap() or BitmapDescriptorFactory.fromResource(). As the exception hints, descriptor got unmanaged on a old marker, better use new one.

I found this happening when accessing marker after it was removed. Interacting with marker in callback is exactly that case. As mentioned in Map's API:

After a marker has been removed, the behavior of all its methods is undefined. https://developers.google.com/android/reference/com/google/android/gms/maps/model/Marker.html#remove()

Best option would be checking is marker removed from map or not.
But we don't have such API. And I found another workaround, we can use Marker's setTag and getTag. Tag is set to null, when marker is removed:

Google Maps Android API neither reads nor writes this property, except that when a marker is removed from the map, this property is set to null. https://developers.google.com/android/reference/com/google/android/gms/maps/model/Marker.html#setTag(java.lang.Object)

When creating marker use some tag for it.
When updating marker check tag is not null.

This could help in your case.

@Override
protected void onClusterItemRendered(Sucursal clusterItem, Marker marker) {
    // we don't care about tag's type so don't reset original one
    if (marker.getTag() == null) {
        marker.setTag("anything");
    }
    CustomSimpleTarget simpleTarget = new CustomSimpleTarget();
    simpleTarget.sucursal = clusterItem;
    simpleTarget.markerToChange = marker;
    ImageLoaderManager.setImageFromId(simpleTarget, clusterItem.logo, mContext);
}

And in callback

private class CustomSimpleTarget extends SimpleTarget<GlideDrawable> {
    ...

    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
        ...

        // if found - change icon
        if (markerToChange != null) {
            //GlideShortcutDrawable is a WeakReference<>(drawable)
            sucursal.setGlideShortCutDrawable(resource);
            if (markerToChange.getTag != null) {
                markerToChange.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
            }
        }
    }
}

This exception happens when your marker was reclustered by ClusterManager. ClusterManager recreates marker on clustering. So, to avoid it you must get your marker from render of ClusterManeger:

ClusterIconRender render = (ClusterIconRender) mClusterManager.getRenderer();
Marker trueMarker = render.getMarker(clusterMarker);
if (trueMarker != null) {
    trueMarker.setIcon(...);
    ... // do whatever else your want with marker
}

In code above ClusterMarker implements ClusterItem and ClusterIconRender extends DefaultClusterRenderer.

I have the same environment (maps-utils + custom renderer + Glide) and the same error IllegalArgumentException: Unmanaged descriptor.

I solved the error by checking if the marker is "valid" before setting the icon, using the methods DefaultClusterRenderer.getCluster(Marker) and DefaultClusterRenderer.getClusterItem(Marker). If both return null, I don't do anything on the onResourceReady(...) method.

In your case I would try the following change to CustomSimpleTarget:

private class CustomSimpleTarget extends SimpleTarget<GlideDrawable> {
    Sucursal sucursal;
    Marker markerToChange = null;

    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {

        if (getCluster(markerToChange) != null || getClusterItem(markerToChange) != null) {

            mImageView.setImageDrawable(resource);
            //currentSelectedItem is the current element selected in the map (Sucursal type)
            //mIconGenerator is a: CustomIconGenerator extends IconGenerator
            if (currentSelectedItem != null && sucursal.idalmacen.contentEquals(currentSelectedItem.idalmacen))
                mIconGenerator.customIconBackground.useSelectionColor(true, ContextCompat.getColor(mContext, R.color.colorAccent));
            else
                mIconGenerator.customIconBackground.useSelectionColor(false, 0);

            Bitmap icon = mIconGenerator.makeIcon();

            //GlideShortcutDrawable is a WeakReference<>(drawable)
            sucursal.setGlideShortCutDrawable(resource);
            markerToChange.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
        }
    }
}

PS.: I can reproduce the problem easily on a slow device and clearing the app cache before testing (to force Glide to load from network). Then I open the map and perform some zoom in/out before any markers load.

Make sure the icon that you are using for marker should not be vector,it should be .png image.

I fixed it by calling the following method.

clusterManager.clearItems()

After that, you can set bitmap to the markers.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!