Android位图imageview内存泄漏

Android位图imageview内存泄漏,android,memory-leaks,bitmap,imageview,out-of-memory,Android,Memory Leaks,Bitmap,Imageview,Out Of Memory,我将4x4 imageView放入一个活动(BoardActivity),用户可以通过单击来更改图像。有了HTC Desire(安卓2.2.2),我在大约30分钟的密集使用中获得了OOM(内存不足)-编辑:这项活动的第16个开始-,但没有其他设备能产生OOM(安卓2.1和安卓2.2.1)。是否可能是我在使用位图/图像视图时犯了一些错误,导致了此错误? 首先,我将所有资源ID加载到映射中: private Map<String, Integer> imageResourceMap; i

我将4x4 imageView放入一个活动(BoardActivity),用户可以通过单击来更改图像。有了HTC Desire(安卓2.2.2),我在大约30分钟的密集使用中获得了OOM(内存不足)-编辑:这项活动的第16个开始-,但没有其他设备能产生OOM(安卓2.1和安卓2.2.1)。是否可能是我在使用位图/图像视图时犯了一些错误,导致了此错误? 首先,我将所有资源ID加载到映射中:

private Map<String, Integer> imageResourceMap;
imageResourceMap = new HashMap<String, Integer>();
        imageResourceMap.put("a", R.drawable.a);
        imageResourceMap.put("b", R.drawable.b);
        imageResourceMap.put("c", R.drawable.c);
//... I store 55 drawable's resourceId in this map
当我需要更改图像时,我只需更改其资源:

imageViews[i][j].setImageBitmap(imageBitmap.get("a"));
在我完成活动之前,我循环使用位图映射:

private void recycleImageBitmaps() {
    for (Bitmap b : imageBitmap.values()) {
        if (b != null) {
            b.recycle();
        }
    }

}
在AndroidManifest.xml中,我将此活动声明为“singleTask”:

HTC在此次活动的第11次开始时仍然崩溃

编辑: 此活动(BoardActivity)从活动(MenuActivity)启动,该活动有4个imageButton,位于Tabhost活动中。imageButtons声明如下所示:

private Bitmap getBitmapFromRes(int resId, int imageSize) {
    Bitmap tmp = null;
    Bitmap b = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        InputStream fis = getResources().openRawResource(resId);
        tmp = BitmapFactory.decodeStream(fis, null, o);
        fis.close();

        int scale = 1;
        if (o.outHeight > imageSize || o.outWidth > imageSize) {
            scale = (int) Math.pow(2, (int) Math.round(Math.log(imageSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = getResources().openRawResource(resId);
        b = BitmapFactory.decodeStream(fis, null, o2);
        fis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }finally{
        if(tmp != null){
            tmp.recycle();
            tmp = null;
        }
    }
    return b;
}
<ImageButton
    android:id="@+id/game_menu_CreateButton"
    android:layout_width="120dip" 
    android:layout_height="120dip"
    android:layout_alignRight="@+id/textView1"
    android:layout_alignTop="@+id/textView1"
    android:background="@drawable/create" 
    android:layout_marginRight="1sp"
    android:layout_marginTop="10sp"
     />


当我从MenuActivity启动BoardActivity时,我不会在MenuActivity调用
finish()
,当我在BoardActivity调用
finish()
时,我不会启动新的意图,所以它只会返回到已经打开的MenuActivity。在这16轮中,我得到了OOM。

为了减少内存,您可以尝试以下方法:

  • 将Drawable转换为位图后,可以将imageResourceMap设置为null。这将卸载3个可牵引电缆
  • 避免存储对ImageView的引用。即使从UI中删除了ImageView,您也可能正在存储它们
  • 更频繁地回收位图。当您知道一个位图没有被使用时,您可以回收它,而不仅仅是onDestroy

编辑:根据注释中的对话:BitmapFactory.decodeStream(fis,null,o)返回的位图未分配给任何变量,因此不会回收。安卓2.2和2.3在这方面会有漏洞。

您希望的HTC操作系统版本是什么?你需要缓存位图吗?gwhy这行没有分配给位图吗<代码>位图工厂.decodeStream(fis,null,o)啊,我明白了,只需设置解码边界。无法删除我的tablet web浏览器上的评论!如果我没有缓存位图,那么我需要在每次图像更改时调整可绘制位图的大小并回收旧位图。我试图通过caching.HTC Desire在Android 2.2.2上运行来避免这种情况,还有另外两台设备没有OOM问题,分别是2.2.1和2.1。实际上,我在imageResourceMap中存储了55个drawable的resourceId,我现在就尝试在获得位图后将其设置为null。但是imageViews数组在活动完成之前一直在使用,在活动完成之前,我可能需要每个位图,因此我无法回收它们。o.inpurgable=true;o2.InPurgable=真;可能会有帮助。(编辑问题)试过了,现在我在活动的第16个开始就得到了OOM。除了位图之外,还有其他类型的位图需要循环使用,但不足以将其设置为null吗?您确定要在活动的onDestroy中调用recycleImageBitmaps()吗?是的,我确定。我把它放到onDestroy中,在调用finish()之前,我也调用了它。我将断点放入recycleImageBitmaps()中,它在需要的地方停止,并在for循环中执行50轮。(使b.回收()
<activity android:name=".game.board.BoardActivity" android:launchMode="singleTask">
    </activity>
private Bitmap getBitmapFromRes(int resId, int imageSize) {
    Bitmap tmp = null;
    Bitmap b = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        InputStream fis = getResources().openRawResource(resId);
        tmp = BitmapFactory.decodeStream(fis, null, o);
        fis.close();

        int scale = 1;
        if (o.outHeight > imageSize || o.outWidth > imageSize) {
            scale = (int) Math.pow(2, (int) Math.round(Math.log(imageSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = getResources().openRawResource(resId);
        b = BitmapFactory.decodeStream(fis, null, o2);
        fis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }finally{
        if(tmp != null){
            tmp.recycle();
            tmp = null;
        }
    }
    return b;
}
<ImageButton
    android:id="@+id/game_menu_CreateButton"
    android:layout_width="120dip" 
    android:layout_height="120dip"
    android:layout_alignRight="@+id/textView1"
    android:layout_alignTop="@+id/textView1"
    android:background="@drawable/create" 
    android:layout_marginRight="1sp"
    android:layout_marginTop="10sp"
     />