Android OutOfMemoryError位图大小超出VM预算

3

我有一个应用程序,其中读取一些GPS数据并在地图上显示它们,同时还会在该位置添加一个小的.png图像覆盖层。

我在一个Async Task线程中读取数据,并在onProgressUpdate方法中通过在新位置添加覆盖层来更新GUI。以下是我的代码:

     Drawable marker;          
public void onCreate(Bundle savedInstanceState) {
            marker=getResources().getDrawable(R.drawable.curent_loc);
    marker.setBounds(0, 0, marker.getIntrinsicWidth(),
            marker.getIntrinsicHeight());

    }

我在这里读取GPS数据:

public class InitTask extends AsyncTask<Void, GeoPoint, Void> {
protected Void doInBackground(Void... voids) {

        p = new GeoPoint(latitude, longitude);
                    publishProgress(p);
                    Thread.sleep(1500);
                }

/*in here I update my GUI*/
  protected void onProgressUpdate(GeoPoint... progress1) {
    mapView.getOverlays().add(new SitesOverlay(marker,progress1[0]));
                theRouteDraw(progress1[0]);
                }
        }

我读取了一个新的位置,并在该位置添加了一个覆盖层。为此,我使用了我的类SitesOverlay,它继承自Overlay

一切都进行得很顺利,直到某个时刻我收到以下异常:

java.lang.OutOfMemoryError: bitmap size exceeds VM budget
 at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:392)
at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:405)
at com.google.android.maps.StreetViewRenderer.getOverlay(StreetViewRenderer.java:149)
com.google.android.maps.StreetViewRenderer.renderTile(StreetViewRendere
at    com.google.android.maps.AndroidTileOverlayRenderer.renderTile(AndroidTileOverlayRenderer.java:62)
at com.google.googlenav.map.Map.drawTile(Unknown Source)
at com.google.googlenav.map.Map.drawMapBackground(Unknown Source)
at com.google.googlenav.map.Map.drawMap(Unknown Source)
at com.google.android.maps.MapView.drawMap(MapView.java:1029)
at com.google.android.maps.MapView.onDraw(MapView.java:468)
at android.view.View.draw(View.java:6535)
at android.view.ViewGroup.drawChild(ViewGroup.java:1531)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
at android.view.ViewGroup.drawChild(ViewGroup.java:1529)

我尝试着回收我的可绘制对象,但是仍然出现了错误。过了一会儿,我发现了这个:

//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
    try {
        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f),null,o);

        //The new size we want to scale to
        final int REQUIRED_SIZE=70;

        //Find the correct scale value. It should be the power of 2.
        int width_tmp=o.outWidth, height_tmp=o.outHeight;
        int scale=1;
        while(true){
            if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                break;
            width_tmp/=2;
            height_tmp/=2;
            scale*=2;
        }

        //Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}
    return null;
}

我在这里找到了一个关于“将图像加载到位图对象时出现奇怪的内存问题”的解决方法:Strange out of memory issue while loading an image to a Bitmap object

但我有几个理解上的问题:

*首先,为什么要使用File f作为参数?这是我想要使用的可绘制对象吗?每次使用该可绘制对象时都必须这样做吗,还是只需要在onCreate()中执行一次即可?

因此,如果有人能够解释如何使用它,我将不胜感激,或者如果您有更简单的解决方案,那就更好了。

1个回答

2
这一直是Android存在的一个很大的问题。Bitmap类、getDrawable函数等都依赖于底层的bitmap.h,该文件作为NDK的一部分提供。每当getDrawable返回一个位图时,由于某种原因,Android在我们不再需要它时并没有正确释放内存。
我使用的一个解决方法是在某个地方创建一个单独的静态位图实例,并在需要时将其弱引用。这样,至少有一个位图实例被加载到内存中。
希望这能帮到你。

1
可以给我展示一下你的代码吗,看看你是怎么做的?因为我刚开始学习编程,这对我来说并不容易。谢谢 :) - adrian
你可能想要查看这个 - https://dev59.com/-m855IYBdhLWcg3wsWhq :) - Mahadevan Sreenivasan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接