Android 位图 imageview 内存泄漏 [英] Android bitmap imageview memory leak

查看:35
本文介绍了Android 位图 imageview 内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I put 4x4 imageView to an activity(BoardActivity), and user can change the images by clicking them. With HTC Desire (Android 2.2.2), I got OOM(Out Of Memory) in about 30 minutes of intensive useage - 16th start of this activity-, but no other devices produces this (android 2.1, and android 2.2.1). Is it possible, that I made some mistake with the bitmap/imageview useage and that causes this error? First, I load all resource ID into a map:

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

然后我调整每个图像的大小并将其保存到位图中,以 Map 表示:

Then I resize and save every image into bitmap, represented in Map:

private static Map<String, Bitmap> imageBitmap;

    private void loadBitmaps(int imagesSize) {

    for (String s : imageResourceMap.keySet()) {
        Bitmap tmp = getBitmapFromRes(imageResourceMap.get(s), imagesSize);
        imageBitmap.put(s, tmp);
    }
}

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

        InputStream fis = getResources().openRawResource(resId);
        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();
    }
    return b;
}

我将图像视图保存在一个数组中,并使用此函数初始化所有图像:

I keep the imageViews in an array, and init all images with this function:

private static ImageView[][] imageViews;

private ImageView getImage(String name) {
        MyImageView item = new MyImageView(this, i, j, c + "");
        item.setImageBitmap(imageBitmap.get(name));
        item.setAdjustViewBounds(true);
        return item;
    }

当我需要更改图像时,我只需更改其资源:

When I need to change an image, I simple change its resource:

imageViews[i][j].setImageBitmap(imageBitmap.get("a"));

在我完成活动之前,我回收位图:

And right before I finish the activity, I recycle the bitmap map:

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

}

在 AndroidManifest.xml 我声明了这个活动singleTask":

In AndroidManifest.xml I declared this activity "singleTask":

<activity android:name=".game.board.BoardActivity" android:launchMode="singleTask">
    </activity>

在此应用程序(游戏)中,我们多次重新打开此活动...我做错了什么?这会导致 Out Of Memory 错误吗?

In this application(game), we reopen this activity a several times... What did I wrong? Can this cause the Out Of Memory error?

更正像这样更正了 getBitmapFromRes:

CORRECTION Corrected the getBitmapFromRes like this:

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;
}

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

HTC still crashed at the 11th start of this activity.

此活动(BoardActivity)从具有 4 个 imageButton 的 Activity(MenuActivity)启动,并且位于 Tabhost 活动中.imageButtons 声明如下所示:

This activity(BoardActivity) launch from an Activity(MenuActivity), which have 4 imageButton, and is in a Tabhost activity. The imageButtons declarations look like this:

<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() 时,我不会't 开始一个新的意图,所以它只是返回到已经打开的 MenuActivity.而这16轮,我就OOM了.

When I start the BoardActivity from MenuActivity, I don't call finish() at MenuActivity, and when I call finish() at the BoardActivity, I don't start a new intent, so it just return to the already opened MenuActivity. And the 16 round of this, I got the OOM.

推荐答案

为了减少内存,你可以试试这些东西:

To reduce memory, you can try out these things :

  • 将drawables转换为位图后,可以将imageResourceMap设置为null.这将卸载 3 个可绘制对象.
  • 避免存储对 imageViews 的引用.即使从 UI 中删除,您也可能会存储 imageViews
  • 更频繁地回收位图.不只是 onDestroy,只要你知道一个位图没有被使用,你就可以回收它.

基于评论中的对话:BitmapFactory.decodeStream(fis, null, o) 返回的位图未分配给任何变量,因此不会被回收.Android 2.2 和 2.3 这行会有漏洞.

Edit : based on the conversation in the comments : The bitmap returned by BitmapFactory.decodeStream(fis, null, o) is not assigned to any variable and hence is not recycled. Android 2.2 and 2.3 will have leaks in this line.

这篇关于Android 位图 imageview 内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆