【问题标题】:Android creating BitmapDescriptor exceptionAndroid 创建 BitmapDescriptor 异常
【发布时间】:2016-04-25 13:28:25
【问题描述】:

我正在编写一个与谷歌地图和标记一起工作的应用程序。我的任务是在谷歌地图上创建和显示一些标记。标记中有自定义图像和文本。数据正在从服务器加载,每次用户移动谷歌地图相机时我都需要显示新的数据量。所以我使用 android-maps-utils:0.4.3 库来创建自定义位图(使用 IconGenerator),然后从中创建 BitmapDescriptor。以下是部分代码:

  googleMap.clear()

        LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        IconGenerator clusterIconGenerator = new IconGenerator(getActivity());
        View clusterView = layoutInflater.inflate(R.layout.marker_cluster_view, null, false);
        clusterIconGenerator.setContentView(clusterView);
        clusterIconGenerator.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.mark_normal_grey));

        List<Cluster> clusters = result.getResult();  // server data

        for (Cluster cluster : clusters) {
            Bitmap bitmap = clusterIconGenerator.makeIcon(String.valueOf(cluster.getOffersCount()));

            Marker marker = googleMap.addMarker(new MarkerOptions()
                    .position(new LatLng(cluster.getLocation().getLatitude(), cluster.getLocation().getLongitude()))
                    .icon(BitmapDescriptorFactory.fromBitmap(bitmap))  // crash here
                    .anchor(0.5f, 0.5f));

            markerClusterMap.put(marker, cluster);
        }

一切都很好,除了应用程序有时(不是经常)崩溃,有 2 个不同的例外:

  java.lang.RuntimeException: Could not copy bitmap to parcel blob.
                                                                     at android.graphics.Bitmap.nativeWriteToParcel(Native Method)
                                                                     at android.graphics.Bitmap.writeToParcel(Bitmap.java:1541)
                                                                     at com.google.android.gms.maps.model.a.c.a(:com.google.android.gms:237)
                                                                     at com.google.android.gms.maps.internal.h.a(:com.google.android.gms:227)
                                                                     at com.google.android.gms.maps.internal.j.a(:com.google.android.gms:183)
                                                                     at com.google.android.gms.maps.internal.CreatorImpl.a(:com.google.android.gms:32)
                                                                     at com.google.android.gms.maps.internal.b.a(:com.google.android.gms:227)
                                                                     at com.google.android.gms.maps.model.a.b.onTransact(:com.google.android.gms:106)
                                                                     at android.os.Binder.transact(Binder.java:387)
                                                                     at com.google.android.gms.maps.model.internal.zza$zza$zza.zzc(Unknown Source)
                                                                     at com.google.android.gms.maps.model.BitmapDescriptorFactory.fromBitmap(Unknown Source)
                                                                     at com.cheapsta.cheapsta.fragments.GoogleMapFragment.clustersLoadingFinished(GoogleMapFragment.java:187)

有时

java.lang.RuntimeException: Could not allocate dup blob fd.
                                                                       at android.graphics.Bitmap.nativeCreateFromParcel(Native Method)
                                                                       at android.graphics.Bitmap.-wrap0(Bitmap.java)
                                                                       at android.graphics.Bitmap$1.createFromParcel(Bitmap.java:1516)
                                                                       at android.graphics.Bitmap$1.createFromParcel(Bitmap.java:1515)
                                                                       at maps.bx.a$a.onTransact(:com.google.android.gms.alldynamite:101)
                                                                       at android.os.Binder.transact(Binder.java:387)
                                                                       at com.google.android.gms.maps.model.a.c.a(:com.google.android.gms:242)
                                                                       at com.google.android.gms.maps.internal.h.a(:com.google.android.gms:227)
                                                                       at com.google.android.gms.maps.internal.j.a(:com.google.android.gms:183)
                                                                       at com.google.android.gms.maps.internal.CreatorImpl.a(:com.google.android.gms:32)
                                                                       at com.google.android.gms.maps.internal.b.a(:com.google.android.gms:227)
                                                                       at com.google.android.gms.maps.model.a.b.onTransact(:com.google.android.gms:106)
                                                                       at android.os.Binder.transact(Binder.java:387)
                                                                       at com.google.android.gms.maps.model.internal.zza$zza$zza.zzc(Unknown Source)
                                                                       at com.google.android.gms.maps.model.BitmapDescriptorFactory.fromBitmap(Unknown Source)
                                                                       at com.cheapsta.cheapsta.fragments.GoogleMapFragment.clustersLoadingFinished(GoogleMapFragment.java:187)

我能用这个做什么?我想我正在使用我的记忆来创建 BitmapDescriptors。如果用户移动相机太多,每 3 秒就有近 20 个 BitmapDescriptos。我应该以某种方式缓存它吗?非常感谢您的回答和时间!

【问题讨论】:

    标签: java android google-maps google-maps-markers google-maps-android-api-2


    【解决方案1】:

    这就是我得到的。看起来如果 BitmapFactory 没有足够的内存,它就无法创建 Bitmap。因此,如果 GC 没有完成工作并且您没有足够的内存,您将收到此异常。就我而言,这很常见,因为每次用户移动谷歌地图相机时,我都需要生成大约 10-20 个标记。

    首先不要像我一样愚蠢,不要只为 IconGenerator 使用 android-maps-utils :) 我编写了自己的类,从 Bitmap 生成 BitmapDescriptor 并将其缓存在 LruCache 中。 Here's good tutorial 用于缓存位图。您可以对 BitmapDescriptor 执行几乎相同的操作。注意 LruCache 的大小。您无法以字节为单位获取 BitmapDescriptor 大小,因此您需要考虑 LruCache 中这些对象的数量。只需查看您的位图大小并进行一些计算。

    如果您需要图片中的文字,请执行以下操作:

    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.mark_active_grey).copy(Bitmap.Config.ARGB_8888, true);
    
        Canvas canvas = new Canvas(bitmap);
        canvas.drawText(offersCount,
                canvas.getWidth()/2,
                canvas.getHeight()/2 - ((clustersPaint.getFontMetrics().ascent + clustersPaint.getFontMetrics().descent) / 2) ,
                clustersPaint);
    

    抱歉英语不好,我希望这些信息对某些人有用。

    【讨论】:

    • 你有IconGeneratorLruCache 对应BitmapDescriptor 的例子吗,特别是你如何解决sizeOf 的位图大小问题?
    • 我现在没有我的 IconGenerator 的例子。但是其中的 LruCache 与关于缓存位图的 Google 教程中的几乎相同(链接在我的分析器中)。是的 sizeOf 是一个问题。我刚刚计算了 Bitmap 的内存大小,并建议 BitmapDescriptor 的大小几乎相同。所以我计算出大小 = 100 BitMapDescriptors 的 LruCach 最大内存为 1.6 mb。一切都很好。我完全没有任何记忆问题。
    【解决方案2】:

    我有同样的问题。根据 Kuva 的回答,我创建了一个这样的新课程:

    public class MapBmpContainter
    {
        private int mBmpSize;
        public BitmapDescriptor mBmpDescriptor;
    
        public MapBmpContainter(Bitmap bmp)
        {
            mBmpSize=bmp.getByteCount()/1014;
            mBmpDescriptor= BitmapDescriptorFactory.fromBitmap(bmp);
        }
    
        public int getSize()
        {
            return mBmpSize;
        }
    }
    

    我在 LruCache 而不是 Bitmap 中缓存新的类对象。 与 Kuva 相同,我认为 Bitmap 和 BitmapDescriptor 的大小几乎相同。 它奏效了

    【讨论】:

    • 为什么是 1014 而不是 1024 ?错别字?
    【解决方案3】:

    对我来说,问题与图标的大小有关。我只是动态更改位图的大小并且工作正常。

    位图 image2 = Bitmap.createScaledBitmap(iconBitmap, 120, 120, false);

    【讨论】:

      【解决方案4】:

      使用 Picasso 、 Glide 或 Fresco Literary 高效缓存位图。

       Picasso.with(getContext())
         .load(R.drawable.marker)
         .resize(width, width)
          .into(new Target() {
         @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
         markerOptionsHome = new MarkerOptions();
         markerOptionsHome.title("Home location");
         markerOptionsHome.snippet("");
         markerOptionsHome.position(latlng);
         markerOptionsHome.icon(BitmapDescriptorFactory.fromBitmap(bitmap));
         homeLocationMarker = map.addMarker(markerOptionsHome);
      
                  }
      
          @Override
         public void onBitmapFailed(Drawable errorDrawable) { }
           @Override
          public void onPrepareLoad(Drawable placeHolderDrawable) {  }
                });
      

      【讨论】:

      • 执行BitmapDescriptorFactory.fromBitmap(bitmap)需要一些时间。我们应该缓存BitmapDescriptor
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多