IllegalArgumentException: неуправляемый дескриптор с использованием gms.maps.model.Marker.setIcon

У меня есть приложение, использующее android-maps-utils и скольжение для значков маркеров .
Я получил сообщение об ошибке с использованием отчетов о gms.maps.model.Marker.setIcon Firebase, которые я не могу отслеживать в исходном коде, потому что gms.maps.model.Marker.setIcon является закрытым, поэтому я прошу о помощи в gms.maps.model.Marker.setIcon этой проблемы.
Следующая часть вопроса разделена на:

  • Что пользователь делал
  • О какой пожарной аварии сообщили мне
  • Некоторые конфигурации проекта
  • Что я пытался / нашел, пытаясь понять / исправить

Что пользователь делал
Он увеличивал и увеличивал масштаб изображения на карте ( Fragment который использует com.google.android.gms.maps.SupportMapFragment )

О какой пожарной аварии сообщили мне

Исключение java.lang.IllegalArgumentException: Неуправляемый дескриптор
Com.google.maps.api.android.lib6.common.kb (: com.google.android.gms.DynamiteModulesB: 162)
Com.google.maps.api.android.lib6.impl.oc (: 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)
Соу.
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)

А также:

Введите описание изображения здесь

Некоторые конфигурации проекта

  • Я использую Custom Render ( SucursalRender extends DefaultClusterRenderer<Sucursal> )
  • Я загружаю значок маркера с помощью Glide, как я уже говорил: Glide.with(context).load(id).fitCenter().placeholder(R.drawable.ic_no_image).into(simpleTarget);

simpleTarget – это то, где я обрабатываю изображения, загруженные / кэшированные для Glide. Я размещаю весь код про simpleTarget потому что крушение начинается там:

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

Авария бросается в последнюю строку кода: markerToChange.setIcon(BitmapDescriptorFactory.fromBitmap(icon));

Что я пытался / нашел, пытаясь понять / исправить

  • Пытался воспроизвести ошибку в 4 реальных устройствах без успеха.
  • Поиск в Интернете для подобных ошибок или кода о gms.maps.model.Marker.setIcon или com.google.maps.api.android.lib6
  • Пытался понять запутанный код, указанный в Android Studio для Marker.setIcon

Наверное, я могу обернуть код в блок try-catch block для этого IllegalArgumentException: неуправляемый дескриптор, чтобы избежать закрытия приложения, потому что авария, но это просто работа вокруг.

Обновление 2
Код 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); } } 

ImageLoaderManager – это просто Facade для 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); } 

Solutions Collecting From Web of "IllegalArgumentException: неуправляемый дескриптор с использованием gms.maps.model.Marker.setIcon"

Я тоже получал такое же исключение, и установка молчащего исключения с try / catch не была бы решением, поскольку пользователь не смог увидеть текущее местоположение в моем случае:

Java.lang.IllegalArgumentException: неуправляемый дескриптор на com.google.maps.api.android.lib6.common.kb (: com.google.android.gms.DynamiteModulesB: 162) на com.google.maps.api.android.lib6 .impl.oc (: 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.mapsel.internal.q.onTransact (: com.google.android.gms.DynamiteModulesB: 204) на android.os.Binder.transact (Binder.java:361) в com. Google.android.gms.maps.model.internal.zzf $ zza $ zza.zzL (Неизвестный источник) в com.google.android.gms.maps.model.Marker.setIcon (Неизвестный источник)

Что я делал:

Минимизируйте экран фрагмента карты, нажав кнопку «домой», а затем запустив приложение из панели запуска.

Какой код выполнял:

Проверка – это маркер не null, а местоположение не имеет нулевого местоположения и значка.

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

Исключение было: markerCurrentLocation.setIcon ();

Как я избавился от этого исключения:

Я удалил следующую строку

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

Это означает, что я снова инициализирую маркер. Если вы столкнулись с этой ошибкой, постарайтесь не устанавливать значение Icon () на старый маркер, а вместо этого надуть новый маркер, а затем использовать setIcon ().

Объяснение:

Я НЕ ПРИНИМАЮ (исключаю) исключительную причину, заключающуюся в том, что код снова пытается установить идентификатор () снова на маркер, на котором он уже установлен, в конкретном экземпляре, например, в моем случае Карта возобновляется или может быть в вашем случае маркер выходит из видимой части Карта и входит или что-то подобное.

Наверняка нет проблем с дескриптором, который мы получаем из метода BitmapDescriptorFactory.fromBitmap () или BitmapDescriptorFactory.fromResource (). В качестве подсказок исключений дескриптор был неуправляемым на старом маркере, лучше использовать новый.

Я обнаружил, что это происходит при доступе к маркеру после его удаления. Взаимодействие с маркером в обратном вызове именно в этом случае. Как упоминалось в API карты:

После удаления маркера поведение всех его методов не определено. https://developers.google.com/android/reference/com/google/android/gms/maps/model/Marker.html#remove ()

Лучшим вариантом будет проверка удаления маркера с карты или нет.
Но у нас нет такого API. И я нашел другое обходное решение, мы можем использовать setTag и getTag . При установке маркера значение тега равно нулю:

API Google Maps Android API не читает и не записывает это свойство, за исключением того, что при удалении маркера с карты это свойство имеет значение null. https://developers.google.com/android/reference/com/google/android/gms/maps/model/Marker.html#setTag(java.lang.Object)

При создании маркера используйте для него несколько тегов.
При обновлении тега проверки маркера не равно null.

Это может помочь в вашем случае.

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

И в обратном вызове

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

У меня такая же среда (maps-utils + custom renderer + Glide) и та же ошибка IllegalArgumentException: Unmanaged descriptor .

Я решил ошибку, проверив, является ли маркер «действительным» перед установкой значка, используя методы DefaultClusterRenderer.getCluster(Marker) и DefaultClusterRenderer.getClusterItem(Marker) . Если оба возвращают null , я ничего не делаю в onResourceReady(...) .

В вашем случае я бы попробовал следующее изменение в 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: Я могу легко воспроизвести проблему на медленном устройстве и очистить кэш приложения перед тестированием (чтобы заставить Glide загружаться из сети). Затем я открываю карту и выполняю некоторое увеличение / уменьшение изображения перед загрузкой маркеров.

Убедитесь, что значок, который вы используете для маркера, не должен быть векторным, это должно быть .png изображение.

Это исключение происходит, когда ваш маркер был повторно ClusterManager . ClusterManager маркер при кластеризации. Таким образом, чтобы избежать этого, вы должны получить маркер от рендера ClusterManeger :

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

В коде выше ClusterMarker реализует ClusterItem и ClusterIconRender расширяет DefaultClusterRenderer .