web-dev-qa-db-fra.com

IllegalArgumentException: descripteur non géré utilisant gms.maps.model.Marker.setIcon

J'ai une application qui utilise Android-maps-utils et glissez pour les icônes de marqueur .
J'ai reçu un rapport d'erreur en utilisant le rapport d'incident Firebase que je ne peux pas suivre dans le code source car gms.maps.model.Marker.setIcon Est privé, donc je demande de l'aide avec ce problème.
La partie suivante de la question est divisée en:

  • Ce que faisait l'utilisateur
  • Quel accident de base de feu m'a signalé
  • Quelques configurations de projet
  • Ce que j'ai essayé/trouvé en essayant de le comprendre/le corriger

Ce que faisait l'utilisateur
Il faisait un zoom avant et arrière sur une carte (Fragment qui utilise com.google.Android.gms.maps.SupportMapFragment)

Quel crash Firebase m'a signalé

Exception Java.lang.IllegalArgumentException: descripteur non géré
com.google.maps.api.Android.lib6.common.k.b (: com.google.Android.gms.DynamiteModulesB: 162)
com.google.maps.api.Android.lib6.impl.o.c (: com.google.Android.gms.DynamiteModulesB: 75)
com.google.maps.api.Android.lib6.impl.db.a (: com.google.Android.gms.DynamiteModulesB: 334)
com.google.Android.gms.maps.model.internal.q.onTransact (: com.google.Android.gms.DynamiteModulesB: 204)
Android.os.Binder.transact (Binder.Java:387)
com.google.Android.gms.maps.model.internal.zzf $ zza $ zza.zzL () com.google.Android.gms.maps.model.Marker.setIcon ()
co.com.spyspot.ui.content.sucursal.SucursalRender $ CustomSimpleTarget.onResourceReady (SucursalRender.Java:156)
co.com.spyspot.ui.content.sucursal.SucursalRender $ CustomSimpleTarget.onResourceReady (SucursalRender.Java:130)
com.bumptech.glide.request.GenericRequest.onResourceReady (GenericRequest.Java:525)
com.bumptech.glide.request.GenericRequest.onResourceReady (GenericRequest.Java:507)
com.bumptech.glide.load.engine.EngineJob.handleResultOnMainThread (EngineJob.Java:158)
com.bumptech.glide.load.engine.EngineJob.access 100 $ (EngineJob.Java:22)
com.bumptech.glide.load.engine.EngineJob $ MainThreadCallback.handleMessage (EngineJob.Java:202)
Android.os.Handler.dispatchMessage (Handler.Java:98)
Android.os.Looper.loop (Looper.Java:148)
Android.app.ActivityThread.main (ActivityThread.Java:5443)
Java.lang.reflect.Method.invoke (Method.Java)
com.Android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.Java:728)
com.Android.internal.os.ZygoteInit.main (ZygoteInit.Java:618)

Et:

enter image description here

Certaines configurations de projet

  • J'utilise un rendu personnalisé (SucursalRender extends DefaultClusterRenderer<Sucursal>)
  • Je télécharge l'icône Marker avec Glide comme je l'ai déjà dit: Glide.with(context).load(id).fitCenter().placeholder(R.drawable.ic_no_image).into(simpleTarget);

Le simpleTarget est l'endroit où je gère les images téléchargées/mises en cache pour Glide. Je publie tout le code sur simpleTarget parce que le crash commence là:

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

    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
        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();

        if (markerToChange == null) {
            for (Marker marker : mClusterManager.getMarkerCollection().getMarkers()) {
                if (marker.getPosition().equals(sucursal.getPosition())) {
                    markerToChange = marker;
                }
            }
        }

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

Le crash est lancé dans la dernière ligne de code: markerToChange.setIcon(BitmapDescriptorFactory.fromBitmap(icon));

Ce que j'ai essayé/trouvé en essayant de le comprendre/le réparer

  • J'ai essayé de reproduire l'erreur sur 4 appareils réels sans succès.
  • Recherche sur le Web d'erreurs ou de codes similaires concernant gms.maps.model.Marker.setIcon Ou com.google.maps.api.Android.lib6
  • J'ai essayé de comprendre le code obscurci donné dans Android Studio pour Marker.setIcon

Je suppose que je peux envelopper le code dans un try-catch block Pour cette IllegalArgumentException: descripteur non géré pour éviter que l'application ne soit fermée parce que le crash mais c'est juste un travail autour.

mise à jour 2
Le code de DefaultClusterRenderer:

public class SucursalRender extends DefaultClusterRenderer<Sucursal> {
    /**
     * Create a customized icon for markers with two background colors. Used with {@link com.google.maps.Android.clustering.ClusterItem}.
     */
    private final CustomIconGenerator mIconGenerator;
    /**
     * Marker image.
     */
    private final ImageView mImageView;
    /**
     * Create a customized icon for {@link Cluster<Sucursal>} with a single background.
     */
    private final IconGenerator mClusterIconGenerator;
    /**
     * Cluster image.
     */
    private final ImageView mClusterImageView;
    private final Context mContext;
    /**
     * Keep a reference to the current item highlighted in UI (the one with different background).
     */
    public Sucursal currentSelectedItem;
    /**
     * The {@link ClusterManager<Sucursal>} instance.
     */
    private ClusterManager<Sucursal> mClusterManager;

    public SucursalRender(Context context, GoogleMap map, ClusterManager<Sucursal> clusterManager) {
        super(context, map, clusterManager);

        mContext = context;
        mClusterManager = clusterManager;
        mIconGenerator = new CustomIconGenerator(mContext.getApplicationContext());
        mClusterIconGenerator = new IconGenerator(mContext.getApplicationContext());

        int padding = (int) mContext.getResources().getDimension(R.dimen.custom_profile_padding);
        int dimension = (int) mContext.getResources().getDimension(R.dimen.custom_profile_image);

        //R.layout.map_cluster_layout is a simple XML with the visual elements to use in markers and cluster
        View view = ((AppCompatActivity)mContext).getLayoutInflater().inflate(R.layout.map_cluster_layout, null);
        mClusterIconGenerator.setContentView(view);
        mClusterImageView = (ImageView) view.findViewById(R.id.image);
        mClusterImageView.setPadding(padding, padding, padding, padding);

        mImageView = new ImageView(mContext.getApplicationContext());
        mImageView.setLayoutParams(new ViewGroup.LayoutParams(dimension, dimension));
        mImageView.setPadding(padding, padding, padding, padding);
        mIconGenerator.setContentView(mImageView);

        CustomIconBackground customIconBackground = new CustomIconBackground(false);
        mIconGenerator.setBackground(customIconBackground);
        mIconGenerator.customIconBackground = customIconBackground;
        mClusterIconGenerator.setBackground(new CustomIconBackground(true));
    }

    ...

    @Override
    protected void onBeforeClusterItemRendered(final Sucursal sucursal, MarkerOptions markerOptions) {

        mImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_no_image));
        Bitmap icon = mIconGenerator.makeIcon();
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
    }

    @Override
    protected void onClusterItemRendered(Sucursal clusterItem, Marker marker) {
        CustomSimpleTarget simpleTarget = new CustomSimpleTarget();
        simpleTarget.sucursal = clusterItem;
        simpleTarget.markerToChange = marker;
        ImageLoaderManager.setImageFromId(simpleTarget, clusterItem.logo, mContext);
    }

    @Override
    protected void onBeforeClusterRendered(Cluster<Sucursal> cluster, MarkerOptions markerOptions) {
        mClusterImageView.setImageDrawable(ResourcesCompat.getDrawable(mContext.getResources(), R.drawable.ic_sucursales, null));
        Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
    }

    @Override
    protected boolean shouldRenderAsCluster(Cluster cluster) {
        // Always render clusters.
        return cluster.getSize() > 1;
    }

    /**
     * Just extends {@link IconGenerator} and give the ability to change background.
     * Used to know highlight the current selected item in UI.
     */
    private class CustomIconGenerator extends IconGenerator {
        private CustomIconBackground customIconBackground;
        private CustomIconGenerator(Context context) {
            super(context);
        }
    }


    /**
     * Create a custom icon to use with {@link Marker} or {@link Cluster<Sucursal>}
     */
    private class CustomIconBackground  extends Drawable {

        private final Drawable mShadow;
        private final Drawable mMask;
        private int mColor = Color.WHITE;

        private boolean useSelectionColor;
        private int mColorSelection;

        private CustomIconBackground(boolean isCluster) {
            useSelectionColor = false;

            if (isCluster) {
                mMask = ContextCompat.getDrawable(mContext, R.drawable.map_pin_negro_cluster);
                mShadow = ContextCompat.getDrawable(mContext, R.drawable.map_pin_transparente_cluster);
            }
            else {
                mMask = ContextCompat.getDrawable(mContext, R.drawable.map_pin_negro);
                mShadow = ContextCompat.getDrawable(mContext, R.drawable.map_pin_transparente);
            }
        }

        public void setColor(int color) {
            mColor = color;
        }

        private void useSelectionColor(boolean value, int color) {
            useSelectionColor = value;
            mColorSelection = color;
        }
        @Override
        public void draw(@NonNull Canvas canvas) {
            mMask.draw(canvas);
            canvas.drawColor(mColor, PorterDuff.Mode.SRC_IN);
            mShadow.draw(canvas);

            if (useSelectionColor) {
                canvas.drawColor(mColorSelection, PorterDuff.Mode.SRC_IN);
                useSelectionColor = false;
            }
        }

        @Override
        public void setAlpha(int alpha) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setColorFilter(ColorFilter cf) {
            throw new UnsupportedOperationException();
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }

        @Override
        public void setBounds(int left, int top, int right, int bottom) {
            mMask.setBounds(left, top, right, bottom);
            mShadow.setBounds(left, top, right, bottom);
        }

        @Override
        public void setBounds(@NonNull Rect bounds) {
            mMask.setBounds(bounds);
            mShadow.setBounds(bounds);
        }

        @Override
        public boolean getPadding(@NonNull Rect padding) {
            return mMask.getPadding(padding);
        }
    }

Le ImageLoaderManager n'est qu'une façade pour Glide.

public static void setImageFromId(SimpleTarget<GlideDrawable> simpleTarget, String id, Context context) {

    if (context instanceof AppCompatActivity) {
        AppCompatActivity activity = (AppCompatActivity)context;
        if (activity.isDestroyed())
            return;
    }
    Glide.with(context)
            .load(id)
            .fitCenter()
            .placeholder(R.drawable.ic_no_image)
            .into(simpleTarget);
}
43
MiguelHincapieC

Lors de l'effacement de la carte avec

    googleMap.clear();

**remove any reference to all the markers** Sur la carte. J'ai eu le problème et j'ai compris que le problème était avec mon code que j'ai oublié de supprimer la référence à un marqueur et j'ai essayé de changer l'icône d'un cleared Marker

14
Morteza Rastgoo

J'obtenais également la même exception et la définition d'une exception silencieuse avec try/catch n'aurait pas été une solution car l'utilisateur n'est pas en mesure de voir l'emplacement actuel dans mon cas:

Java.lang.IllegalArgumentException: descripteur non géré sur com.google.maps.api.Android.lib6.common.kb (: com.google.Android.gms.DynamiteModulesB: 162) sur com.google.maps.api.Android.lib6 .impl.oc (: com.google.Android.gms.DynamiteModulesB: 75) sur com.google.maps.api.Android.lib6.impl.db.a (: com.google.Android.gms.DynamiteModulesB: 334) sur com.google.Android.gms.maps.model.internal.q.onTransact (: com.google.Android.gms.DynamiteModulesB: 204) sur Android.os.Binder.transact (Binder.Java:361) sur com. google.Android.gms.maps.model.internal.zzf $ zza $ zza.zzL (Source inconnue) sur com.google.Android.gms.maps.model.Marker.setIcon (Source inconnue)

Ce que je faisais:

Réduisez l'écran du fragment de carte en appuyant sur le bouton d'accueil, puis en lançant l'application à partir du lanceur.

Quel code faisait:

Vérifier que le marqueur n'est pas nul et que l'emplacement n'est pas nul définir l'emplacement et l'icône.

     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);
                }       
         }

L'exception était à: markerCurrentLocation.setIcon ();

Comment je me suis débarrassé de cette exception:

J'ai supprimé la ligne suivante

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

Ce qui signifie que j'initialise à nouveau le marqueur. Si vous rencontrez cette erreur, essayez de ne pas définir setIcon () sur l'ancien marqueur, au lieu de gonfler le nouveau marqueur, puis utilisez setIcon ().

Explication:

J'ASSUME (pas sûr) que la raison de l'exception était si le code essayait de définir à nouveau SetIcon () sur le marqueur sur lequel il est déjà défini, à un cas particulier comme dans mon cas, la carte reprend ou peut être dans votre cas, le marqueur sort de la partie visible de carte et vient ou quelque chose de similaire.

Pour sûr, il n'y a aucun problème avec le descripteur que nous obtenons de la méthode BitmapDescriptorFactory.fromBitmap () ou BitmapDescriptorFactory.fromResource (). Comme l'indique l'exception, le descripteur n'a pas été géré sur un ancien marqueur, mieux vaut en utiliser un nouveau.

13
Sourab Sharma

J'ai constaté que cela se produisait lors de l'accès au marqueur après sa suppression. Interagir avec le marqueur dans le rappel est exactement ce cas. Comme mentionné dans l'API de Map:

Après la suppression d'un marqueur, le comportement de toutes ses méthodes n'est pas défini. https://developers.google.com/Android/reference/com/google/Android/gms/maps/model/Marker.html#remove ()

La meilleure option serait de vérifier si le marqueur a été retiré de la carte ou non.
Mais nous n'avons pas une telle API. Et j'ai trouvé une autre solution de contournement, nous pouvons utiliser setTag et getTag de Marker. La balise est définie sur null lorsque le marqueur est supprimé:

Google Maps Android ne lit ni n'écrit cette propriété, sauf que lorsqu'un marqueur est supprimé de la carte, cette propriété est définie sur null. https://developers.google. com/Android/reference/com/google/Android/gms/maps/model/Marker.html # setTag (Java.lang.Object)

Lors de la création d'un marqueur, utilisez une balise pour cela.
Lors de la mise à jour, la balise de vérification du marqueur n'est pas nulle.

Cela pourrait vous aider dans votre cas.

@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);
}

Et en rappel

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));
            }
        }
    }
}
11
Stas Parshin

Cette exception se produit lorsque votre marqueur a été reclassé par ClusterManager. ClusterManager recrée le marqueur sur le clustering. Donc, pour l'éviter, vous devez obtenir votre marqueur à partir du rendu de ClusterManeger:

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

Dans le code ci-dessus, ClusterMarker implémente ClusterItem et ClusterIconRender étend DefaultClusterRenderer.

3
Nikita Levanov

J'ai le même environnement (maps-utils + rendu personnalisé + Glide) et la même erreur IllegalArgumentException: Unmanaged descriptor.

J'ai résolu l'erreur en vérifiant si le marqueur est "valide" avant de définir l'icône, en utilisant les méthodes DefaultClusterRenderer.getCluster(Marker) et DefaultClusterRenderer.getClusterItem(Marker). Si les deux renvoient null, je ne fais rien sur la méthode onResourceReady(...).

Dans votre cas, j'essaierais la modification suivante en 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.: Je peux facilement reproduire le problème sur un appareil lent et vider le cache de l'application avant de tester (pour forcer Glide à se charger depuis le réseau). Ensuite, j'ouvre la carte et effectue un zoom avant/arrière avant le chargement des marqueurs.

2
user2595794

Assurez-vous que l'icône que vous utilisez pour le marqueur ne doit pas être vectorielle, mais plutôt une image .png.

0
Harmantj

Je l'ai corrigé en appelant la méthode suivante.

clusterManager.clearItems()

Après cela, vous pouvez définir le bitmap sur les marqueurs.

0
user3813078