Android 创建 BitmapDescriptor 异常
Android creating BitmapDescriptor exception
我正在编写一个应用程序,它与 google 地图和标记一起工作。我的任务是在 google 地图上创建和显示一些标记。标记中包含自定义图像和文本。数据正在从服务器加载,每次用户移动 google 地图相机时我都需要显示新的数据量。所以我使用 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.createFromParcel(Bitmap.java:1516)
at android.graphics.Bitmap.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。我应该以某种方式缓存它吗?非常感谢您的回答和时间!
好吧,这就是我得到的。看起来如果 BitmapFactory 没有足够的内存就无法创建位图。因此,如果 GC 没有完成工作并且您没有足够的内存,您将得到这个异常。在我的例子中,这很常见,因为每次用户移动 google 地图相机时我都需要生成大约 10-20 个标记。
首先不要像我一样愚蠢,不要只为 IconGenerator 使用 android-maps-utils :) 我自己写了 class 从位图和缓存中生成 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);
抱歉英语不好,我希望这些信息对某些人有用。
我有同样的问题。根据 Kuva 的回答,我创建了一个新的 class,如下所示:
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 中缓存新的 class 对象而不是位图。
与 Kuva 相同,我认为 Bitmap 和 BitmapDescriptor 的大小几乎相同。
并且有效
使用 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) { }
});
对我来说,问题与图标的大小有关。我只是动态更改位图的大小并且工作正常。
位图 image2 = Bitmap.createScaledBitmap(iconBitmap, 120, 120, false);
我正在编写一个应用程序,它与 google 地图和标记一起工作。我的任务是在 google 地图上创建和显示一些标记。标记中包含自定义图像和文本。数据正在从服务器加载,每次用户移动 google 地图相机时我都需要显示新的数据量。所以我使用 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.createFromParcel(Bitmap.java:1516)
at android.graphics.Bitmap.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。我应该以某种方式缓存它吗?非常感谢您的回答和时间!
好吧,这就是我得到的。看起来如果 BitmapFactory 没有足够的内存就无法创建位图。因此,如果 GC 没有完成工作并且您没有足够的内存,您将得到这个异常。在我的例子中,这很常见,因为每次用户移动 google 地图相机时我都需要生成大约 10-20 个标记。
首先不要像我一样愚蠢,不要只为 IconGenerator 使用 android-maps-utils :) 我自己写了 class 从位图和缓存中生成 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);
抱歉英语不好,我希望这些信息对某些人有用。
我有同样的问题。根据 Kuva 的回答,我创建了一个新的 class,如下所示:
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 中缓存新的 class 对象而不是位图。 与 Kuva 相同,我认为 Bitmap 和 BitmapDescriptor 的大小几乎相同。 并且有效
使用 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) { }
});
对我来说,问题与图标的大小有关。我只是动态更改位图的大小并且工作正常。
位图 image2 = Bitmap.createScaledBitmap(iconBitmap, 120, 120, false);