【问题标题】:Out of memory Error on setImageResourcesetImageResource 上的内存不足错误
【发布时间】:2013-04-24 04:54:13
【问题描述】:

我正在制作一个棋盘游戏,并且我正在为棋盘使用 10x10 GridView。我制作了一个类 ImageAdapter 扩展 BaseAdapter ,它包含一个整数图标数组(9 个补丁文件),这些用于显示棋盘方格的图像。图标存储在 res/drawable 文件夹中,大小为 629X629,平均大小约为 5 KB。

我的 ImageAdapter 类有以下 getView() 方法,它本质上是回收同一个视图以节省内存:

编辑:(我已包含在游戏的 Activity 中调用的 changeIcon 方法)

public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    if (convertView == null) {  // if it's not recycled, initialize some attributes
        imageView = new ImageView(mContext);
        imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setPadding(8, 8, 8, 8);
    }
    else{
        imageView = (ImageView) convertView;
    }


    imageView.setImageResource(mThumbIds[position]);
    return imageView;
}

public void changeIcon(int x, int y, Integer icon){
    int position = (9-y)*10 + x;
    mThumbIds[position] = icon;
    getView(position, currentView, null);
}

我有一个名为 Game 的单独类,用于处理游戏的逻辑。我将碎片存储在 Piece[][] 数组中,其中 Piece 是我为保存(你猜对了)游戏碎片的数据而创建的另一个类。相关的是处理棋子移动的方法 move(int xFrom, int yFrom, int xTo, int yTo)。我可以整天移动碎片,一切都很好。

但是,一旦我将一块移入另一块,应用程序就会崩溃。预期的行为是创建一个新片段。发生这种情况的代码如下:

public boolean move(int xFrom, int yFrom, int xTo, int yTo){

    boolean success = false;
    Piece pieceToMove = getPiece(xFrom,yFrom);
    Piece pieceAtDest = getPiece(xTo,yTo);
    int moveTeam = pieceToMove.getTeam();

    if(isLegalMove(xFrom, yFrom, xTo, yTo, pieceToMove)&&(turn == moveTeam)){
        if( pieceAtDest == null)
        {
           /*I do something when the destination piece is null; 
                       this block causes no problems */   
        }
        else{
            success = true;
            pieceToMove.merge();
            position[xTo][yTo] = pieceToMove;
            position[xFrom][yFrom] = null;
        }
    }
    return success;
}

因此,有问题的调用是pieceToMove.merge()。 Piece 类中的方法 merge() 只需更改该类中的字段 type (片段变成新的),然后调用该类的方法 setIcon()。此方法根据类型的值设置类的 icon 字段。而且,如上所述,图标是整数,指的是 res/drawable 中的九个补丁文件。

最后,方法 move(int xFrom, int yFrom, int xTo, int yTo) 从 Activity GameBoardActivity 中被调用,在成功移动后,Activity 请求 ImageAdapter(称为 adapter)重绘板子,如下:

boolean success = game.move(xFrom,yFrom,xTo,yTo);

if(success){

Integer destIcon = game.getPiece(xTo, yTo).getIcon();
Piece pieceAtDep = game.getPiece(xFrom, yFrom);
Integer depIcon;
if(pieceAtDep == null)
    depIcon = R.drawable.square;
else
    depIcon = game.getPiece(xFrom, yFrom).getIcon();
adapter.changeIcon(xTo,yTo,destIcon);
adapter.changeIcon(xFrom,yFrom,depIcon);
gridView.setAdapter(adapter);
}

Logcat 说导致“致命信号 11”和“6330272 字节分配内存不足”的行是 ImageAdapter 的 getView 方法中的 imageView.setImageResource(mThumbIds[position]); 行。

所以,就像我说的,一切都很好,直到我需要合并两个部分,然后我得到内存不足的错误。还值得注意的是,这种合并行为在应用程序的早期迭代中运行良好。

现在我应该提一下标准免责声明,因为在 java/android 编码方面我是一个完整的初学者,并且我已经查看了与类似问题相关的其他问题,但似乎没有其他人在处理他们的位图我也是。

非常感谢任何帮助。 非常感谢。

更新

通过进一步的测试,我注意到另一个奇怪的地方,即有时会出现问题,有时不会,而且我无法确定在某些情况下导致崩溃的原因,而在其他情况下则不会。更准确地说,执行完全相同的移动顺序可能会也可能不会导致崩溃。这很神秘。

【问题讨论】:

  • 您应该先创建 thumb,然后再提供图像视图。
  • 你的意思是mThumbIds吗?它是之前创建的,只是不在那个代码 sn-p 中。
  • 如果您的意思是应该创建对图像本身的实际引用,我在发生这种情况的地方包含了 changeIcon 方法。它在 GameBoardActivity 中被调用。

标签: android gridview bitmap out-of-memory


【解决方案1】:

在您的代码中,mThumbIds 是可绘制的 Ids。您应该做的是您必须通过以下代码创建特定图像的 Thumb

public static int calculateInSampleSize(BitmapFactory.Options options,
        int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and
        // width
        final int heightRatio = Math.round((float) height
                / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will
        // guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromResource(Resources res,
        int resId, int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth,
            reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
} 

使用此代码,

decodeSampledBitmapFromResource(getResources(),R.drawable.xyz, 100, 100);

在这里,您提供 100 * 100 的样本大小。所以会创建这样大小的缩略图。

【讨论】:

  • 这就像一个魅力!感谢一百钦坦!就我所知,位图的大小正在按比例缩小,但是我仍然在某处遇到未回收内存的问题吗?当我在屏幕上放更多东西时,这个问题会再次出现吗?为什么这个问题只在某些时候发生而不在其他时候发生?
  • 您可以在使用任何 Bitmap 时使用 SoftReferenceWeakReference,但有时它会返回 null 所以我不会在这个例子中建议。但是您可以在创建任何位图时使用它,并且在进行任何操作之后,您就不需要它了。
  • @ChintanRathod 这是解决问题。不要忘记rectycle()位图onDestory()
猜你喜欢
  • 1970-01-01
  • 2013-05-13
  • 1970-01-01
  • 2018-12-15
  • 2015-09-20
  • 1970-01-01
  • 2015-02-10
相关资源
最近更新 更多