3

我正在編寫一個應用程序,它可以與谷歌地圖和標記一起工作。我的任務是在Google地圖上創建並顯示一些標記。標記具有自定義圖像和文字。數據從服務器加載,我需要顯示新的數據量每次用戶移動谷歌地圖相機。所以我使用android-maps-utils:0.4.3庫來創建自定義位圖(使用IconGenerator),然後從它創建BitmapDescriptor。下面是部分代碼:Android創建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); 
     } 

一切都只是應用OK有時死機(不經常)用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。我應該緩存嗎? Thx很多爲您的答案和時間!

回答

4

那麼這就是我得到的。看起來像BitmapFactory不能創建位圖,如果它沒有足夠的內存。所以如果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); 

對不起,我的英文不好,我希望這個信息將是一些有用的一個。

+0

你有'IconGenerator'用'LruCache'爲'BitmapDescriptor'的例子,你特別是如何在關於位圖大小解決'sizeOf'? – Dellkan

+2

我現在沒有我的IconGenerator的示例。但LruCache與Google教程中關於緩存位圖(在我的配置文件中鏈接)幾乎相同。是的,sizeof是一個問題。我只是計算了我的位圖的內存大小,並建議BitmapDescriptor的大小几乎相同。所以我計算出LruCach的size = 100,BitMapDescriptors的內存最大爲1.6mb。一切都很好。我根本沒有任何記憶問題。 – Kuva

1

我有同樣的問題。隨着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而不是位圖。 與Kuva相同我認爲Bitmap和BitmapDescriptor的大小几乎相同。 它的工作原理

+0

爲什麼1014而不是1024?錯字? –

-1

使用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) { } 
      });