Android 自定义图库小组件因 java.lang.OutOfMemoryError 崩溃:位图大小超出 VM 预算

发布于 2024-12-07 17:17:49 字数 2563 浏览 0 评论 0原文

当在图像库上来回滚动多次时,我的应用程序崩溃并显示:

java.lang.OutOfMemoryError:位图大小超出虚拟机预算

我需要图库垂直显示两个图像:

  • 顶部的图像将是从预图像中选择的图像res/drawable 文件夹中定义的图像组。
  • 如果他们正确回答了该特定图像(这是游戏的提交分数页面),则底部图像将是一个绿色复选标记;如果他们回答错误,则底部图像将是一个带有线的红色圆圈。

这是我扩展 BaseAdapter 的代码:

    public class ImageAdapter extends BaseAdapter {
    int mGalleryItemBackground;
    private Context mContext;

    public ImageAdapter(Context c) {
        mContext = c;
        TypedArray attr = mContext.obtainStyledAttributes(R.styleable.SubmitScoreGallery);
        mGalleryItemBackground = attr.getResourceId(
                R.styleable.SubmitScoreGallery_android_galleryItemBackground, 0);
        attr.recycle();
    }
    @Override
    public int getCount() {

        return numQuestions;
    }

    @Override
    public Object getItem(int position) {

        return position;
    }

    @Override
    public long getItemId(int position) {

        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {


        //Setup a LinearLayout to display the second image
        LinearLayout lLayout = new LinearLayout(this.mContext);
        lLayout.setOrientation(LinearLayout.VERTICAL);
        //Create the ImageView
        ImageView imageView = new ImageView(this.mContext);


        imageView.setImageResource(imageList.get(randOrder.get(position)));
        imageView.setLayoutParams(new Gallery.LayoutParams(gDispW, gDispH));
        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
        imageView.setBackgroundResource(mGalleryItemBackground);
        lLayout.addView(imageView);
        //Create the right/wrong image
        ImageView imageViewBottom = new ImageView(lLayout.getContext());
        if (score.getScoreAtIndex(position)== 1){
            imageViewBottom.setImageResource(R.drawable.green_checkmark);   
        }
        else{
            imageViewBottom.setImageResource(R.drawable.incorrect_circle);
        }
        imageViewBottom.setLayoutParams(new Gallery.LayoutParams(gDispW, gDispH));
        imageViewBottom.setPadding(gDispW/3, 0, gDispW/3, gDispH/2);
        imageViewBottom.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        //imageViewBottom.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        lLayout.addView(imageViewBottom);

       return lLayout;

    }
}

randOrder 是一个保存图像顺序的数组。

图库可保存 5、10 或 15 张图像,具体取决于用户选择的问题数量。

我可以让它与 15 张图像一致地崩溃。

有更好的方法吗?

我做错了什么?

谢谢你,

尼尔

When scrolling back and forth a bunch of times on the image gallery my app crashes with:

java.lang.OutOfMemoryError: bitmap size exceeds VM budget

I need the gallery to show two images vertically:

  • The top one will be a selection from a pre-defined group of images in the res/drawable folder.
  • The bottom image will be a green check mark if they answered this particular image correct (this is the submit your score page of the game) or a red circle with a line through it if they get it wrong.

Here is my code that extends the BaseAdapter:

    public class ImageAdapter extends BaseAdapter {
    int mGalleryItemBackground;
    private Context mContext;

    public ImageAdapter(Context c) {
        mContext = c;
        TypedArray attr = mContext.obtainStyledAttributes(R.styleable.SubmitScoreGallery);
        mGalleryItemBackground = attr.getResourceId(
                R.styleable.SubmitScoreGallery_android_galleryItemBackground, 0);
        attr.recycle();
    }
    @Override
    public int getCount() {

        return numQuestions;
    }

    @Override
    public Object getItem(int position) {

        return position;
    }

    @Override
    public long getItemId(int position) {

        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {


        //Setup a LinearLayout to display the second image
        LinearLayout lLayout = new LinearLayout(this.mContext);
        lLayout.setOrientation(LinearLayout.VERTICAL);
        //Create the ImageView
        ImageView imageView = new ImageView(this.mContext);


        imageView.setImageResource(imageList.get(randOrder.get(position)));
        imageView.setLayoutParams(new Gallery.LayoutParams(gDispW, gDispH));
        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
        imageView.setBackgroundResource(mGalleryItemBackground);
        lLayout.addView(imageView);
        //Create the right/wrong image
        ImageView imageViewBottom = new ImageView(lLayout.getContext());
        if (score.getScoreAtIndex(position)== 1){
            imageViewBottom.setImageResource(R.drawable.green_checkmark);   
        }
        else{
            imageViewBottom.setImageResource(R.drawable.incorrect_circle);
        }
        imageViewBottom.setLayoutParams(new Gallery.LayoutParams(gDispW, gDispH));
        imageViewBottom.setPadding(gDispW/3, 0, gDispW/3, gDispH/2);
        imageViewBottom.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        //imageViewBottom.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        lLayout.addView(imageViewBottom);

       return lLayout;

    }
}

randOrder is an array that holds the order of the images

The gallery holds 5, 10 or 15 images depending on how many questions the user chooses.

I can get it to crash consistently with the 15 images.

Is there a better way to do this?

What am I doing wrong?

Thank you,

Neil

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

牵强ㄟ 2024-12-14 17:17:49

在 getView 方法中,您每次都会创建一个 ImageView。您可以像这样使用convertView:

        ImageView imageView;
        // if it's not recycled, initialize some attributes
        if (convertView == null) {
            imageView = new ImageView(mContext);
        } else {
            imageView = (ImageView) convertView;
        }

此外,您可以在位图上使用重采样。

On getView method, you create an ImageView every time. You can use convertView like this:

        ImageView imageView;
        // if it's not recycled, initialize some attributes
        if (convertView == null) {
            imageView = new ImageView(mContext);
        } else {
            imageView = (ImageView) convertView;
        }

Moreover, you can use resampling on your bitmaps.

单身狗的梦 2024-12-14 17:17:49

此帖子的评论 19:code.google.com 问题 8488 修复了该问题。

我所要做的就是创建文件夹 res/drawable-nodpi 并将我调用的图像放入其中。

由于某种原因,如果您将图像存储在 res/drawable 中,则 attr.recycle() 无法正常工作。有人知道为什么吗?

我还实施了蒂姆的建议,它似乎加快了画廊中来回滚动的速度。谢谢你!

编辑:

上面的答案适用于 myTouch 4g,但程序在 G2 上仍然崩溃。所以我采纳了蒂姆的建议并开始考虑对图像进行重新采样。我最终使用了 Fedor 在这篇文章中的答案:
将图像加载到位图对象时出现奇怪的内存不足问题,我还没有从那以后,G2 上再也没有出现过内存不足的问题。

Comment 19 of this post: code.google.com Issue 8488 fixed the issue.

All I had to do was create the folder res/drawable-nodpi and put the images that I am calling in there.

For some reason if you store your images in res/drawable the attr.recycle() doesn't work right. Anyone know why?

I also implemented Tim's suggestion and it seems to have sped up the scrolling back and forth in the gallery. Thank you!

EDIT:

The above answer worked for a myTouch 4g but the program still crashed with a G2. So I took Tim's advice and started to look at re-sampling images. I ended up using Fedor's answer from this post:
Strange out of memory issue while loading an image to a Bitmap object and I haven't seen the out of memory issues on the G2 since.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文