IllegalArgumentException:使用gms.maps.model.Marker.setIcon的非托pipe描述符

我有一个应用程序,使用android-maps-utils和滑行标记图标 。
我得到了一个错误报告,使用Firebase崩溃报告,我不能在源代码中跟踪,因为gms.maps.model.Marker.setIcon是私人的,所以我要求这个问题的一些帮助。
问题的后续部分分为:

  • 用户在做什么
  • 什么firebase崩溃报告给我
  • 一些项目configuration
  • 我尝试/发现试图理解/修复它

用户在做什么
他在地图上放大缩小(使用com.google.android.gms.maps.SupportMapFragment Fragment

什么firebase崩溃报告给我

exceptionjava.lang.IllegalArgumentException:非托pipe描述符
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)
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)

和:

在这里输入图像说明

一些项目configuration

  • 我正在使用自定义渲染( SucursalRender extends DefaultClusterRenderer<Sucursal>
  • 我正在用Glide下载标记图标,就像我之前说过的: Glide.with(context).load(id).fitCenter().placeholder(R.drawable.ic_no_image).into(simpleTarget);

simpleTarget是我处理为Glide下载/caching的图像的地方。 我发布了关于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个真正的设备错误没有成功。
  • 在web中search有关gms.maps.model.Marker.setIconcom.google.maps.api.android.lib6类似错误或代码
  • 试图了解在Android Studio中为Marker.setIcon提供的混淆代码

我想我可以将代码包装在一个try-catch block用于IllegalArgumentException:非托pipe描述符,以避免应用程序因为崩溃而closures,但这只是一个解决方法。

更新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只是Glide的一个Facade。

 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的非托pipe描述符"

我得到同样的exception和设置沉默exception与try / catch不会解决scheme,因为用户无法看到我的情况下的当前位置:

java.lang.IllegalArgumentException:com.google.maps.api.android.lib6.common.kb上的非托pipe描述符(:com.google.android.gms.DynamiteModulesB:162)com.google.maps.api.android.lib6 (:com.google.android.gms.DynamiteModulesB:75) com.google.android.gms.maps.model.internal.q.onTransact(:com.google.android.gms.DynamiteModulesB:204)在android.os.Binder.transact(Binder.java:361)at com。 google.android.gms.maps.model.internal.zzf $ zza $ zza.zzL(未知来源)位于com.google.android.gms.maps.model.Marker.setIcon(未知来源)

我在做什么:

按住homebutton,然后从启动器启动应用程序,最小化地图片段屏幕。

什么代码在做:

检查标记是否为空,位置不是空集的位置和图标。

  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在:markerCurrentLocation.setIcon();

我如何摆脱这个例外:

我删除了下面一行

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

这意味着我再次初始化标记。 如果遇到此错误,请不要尝试在旧标记上设置图标(),而是膨胀新标记,然后使用setIcon()。

说明:

我假设(不知道)exception的原因是,如果代码试图setIcon()再次在它已经设置的标记,在特定的情况下,就像在我的情况下,地图正在恢复或可能在你的情况标记出去的可见部分地图和进来或类似的东西。

当然,我们从方法BitmapDescriptorFactory.fromBitmap()或BitmapDescriptorFactory.fromResource()获取的描述符没有问题。 作为exception提示,描述符在旧标记上不受pipe理,更好地使用新标记。

删除后,我发现访问标记时发生这种情况。 在callback中与标记进行交互就是这种情况。 正如Map的API所述:

标记被删除后,其所有方法的行为都是未定义的。 https://developers.google.com/android/reference/com/google/android/gms/maps/model/Marker.html#remove(&#xFF09;

最好的select是检查是否从地图上删除标记。
但是我们没有这样的API。 我发现另一个解决方法,我们可以使用Marker的setTaggetTag 。 当标记被删除时,标记被设置为空:

Google Maps Android API既不读取也不写入此属性,只是当从地图中删除标记时,此属性设置为空。 https://developers.google.com/android/reference/com/google/android/gms/maps/model/Marker.html#setTag(java.lang.Object&#xFF09;

创build标记时使用一些标记。
更新标记检查标记时不为空。

这可以帮助你的情况。

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

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

我有相同的环境(maps-utils +自定义渲染器+滑翔)和相同的错误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:我可以很容易地在慢速设备上重现问题,并在testing之前清除应用高速caching(强制Glide从networking加载)。 然后,我打开地图,并执行一些放大/缩小任何标记加载之前。

确保你用于标记的图标不应该是vector,它应该是.png图像。

用清除地图时

  googleMap.clear(); 

**remove any reference to all the markers**地图上**remove any reference to all the markers** 。 我有这个问题,并发现问题是我的代码,我忘记删除对标记的引用,并试图改变已cleared Marker图标

当您的标记由ClusterManager重新聚集时,会发生此exception。 ClusterManager在集群上重新创build标记。 所以,为了避免它,您必须从ClusterManeger呈现中获取标记:

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

在上面的代码中, ClusterMarker实现了ClusterItemClusterIconRender扩展了DefaultClusterRenderer