自定义 GridView 出现内存不足异常

5
我有一个自定义网格视图的代码,每次尝试运行它时,都会因为OutOfMemoryException而崩溃。我猜解决方法是调整数组中的图像大小... 主活动代码:
public class AndroidGridLayoutActivity extends Activity {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.grid_layout);

            GridView gridView = (GridView) findViewById(R.id.grid_view);

            // Instance of ImageAdapter Class
            gridView.setAdapter(new ImageAdapter(this));

            /**
             * On Click event for Single Gridview Item
             * */
            gridView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View v,
                        int position, long id) {

                    // Sending image id to FullScreenActivity
                    Intent i = new Intent(getApplicationContext(), FullImageActivity.class);
                    // passing array index
                    i.putExtra("id", position);
                    startActivity(i);
                }
            });
        }



}

图片适配器代码:
public class ImageAdapter extends BaseAdapter {
    private Context mContext;

    // Keep all Images in array
    public Integer[] mThumbIds = {
            R.drawable.pic_1, R.drawable.pic_2,
            R.drawable.pic_3, R.drawable.pic_4,
            R.drawable.pic_5, R.drawable.pic_6,
            R.drawable.pic_7, R.drawable.pic_8,
            R.drawable.pic_9, R.drawable.pic_10,
            R.drawable.pic_11, R.drawable.pic_12,
            R.drawable.pic_13, R.drawable.pic_14,
            R.drawable.pic_15
    };

    // Constructor
    public ImageAdapter(Context c){
        mContext = c;
    }

    @Override
    public int getCount() {
        return mThumbIds.length;
    }

    @Override
    public Object getItem(int position) {
        return mThumbIds[position];
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {         
        ImageView imageView = new ImageView(mContext);
        imageView.setImageResource(mThumbIds[position]);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setLayoutParams(new GridView.LayoutParams(70, 70));

        return imageView;
    }
}

全屏代码:
public class FullImageActivity extends Activity {


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.full_image);

        // get intent data
        Intent i = getIntent();

        // Selected image id
        int position = i.getExtras().getInt("id");
        ImageAdapter imageAdapter = new ImageAdapter(this);

        ImageView imageView = (ImageView) findViewById(R.id.full_image_view);
        imageView.setImageResource(imageAdapter.mThumbIds[position]);
    }

}

任何建议,请?

3
这些图片有多大? - Simon
这个的尺寸有多大?R.drawable.pic_1 - A.S.
每个文件大小为268,233字节。 - Sereen Shalby
1
@SereenShalby 重要的是尺寸,而不是文件大小。Android将图像读入字节数组中,每个像素存储为四个字节。这相当于“宽度×高度×4”。 - Paul Lammertsma
@PaulLammertsma,请问我该如何修复这个问题? - Sereen Shalby
文件大小并不重要。它们的像素有多大? - Simon
2个回答

2
您正在尝试为图像数据分配过多的内存。正如您在评论中解释的那样,您的图像相当大,并且它们在适配器创建时就被读取了。
将其读入内存将消耗每个像素4个字节,因此如果您的图像是1024个像素的正方形,则计算如下:
  • 1024 × 1024 × 4 = 4MB
  • 15张图片 × 4 MB/张图片 = 60MB
这很可能超出了48MB的堆预算。
您可能希望通过提高显示这些图像的效率来改进。请考虑:
  1. 仅在显示图像时加载图像,使用GridView的机制来获取getView()
  2. 使用BitmapFactory加载具有样本大小的位图。

请问您能否再解释一下吗? - Sereen Shalby
1
经过进一步的审查,看起来您已经(部分地)使用了getView()机制。我建议您在可用时正确地回收视图,而不是每次创建新视图。通过加载缩小的位图,您的问题应该完全被解决。您可能需要考虑使用现有库,例如[Picasso](http://square.github.io/picasso/)。 - Paul Lammertsma

1
针对“在GridView中加载图像”的问题,您可以使用inSampleSize加载所有图像,并通过原始图像替换可见图像。这意味着,动态地为可见部分加载图像,不需要使用BitmapFactory及其Options的inSampleSize。
您可以根据不同设备缩小它们的比例,以便在加载图像时避免内存问题。在您的情况下,某些手机可能在第一次运行时不会表现出相同的行为,但最终,如果没有处理优化的图像加载解决方案,应用程序将崩溃。
主题:将缩小版本加载到内存中。 http://developer.android.com/training/displaying-bitmaps/load-bitmap.html Android上的内存不足错误 如何避免它们: 如何在Android中使用位图时避免内存不足错误

概述:

http://blogs.innovationm.com/android-out-of-memory-error-causes-solution-and-best-practices/ http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html

在为您的ImageView设置Drawable背景之前,请注意:

iv.setBackgroundResource(R.drawable.image);  

获取一个缩放的位图或尝试其他选项,例如 inSampleSize,请确保您的解决方案对图像质量的影响进行检查。
针对评论:
Bitmap drawableImage=BitmapFactory.decodeResource(context.getResources(),R.drawable.image);
Bitmap bitmap = Bitmap.createScaledBitmap(drawableImage, width, height, false);
Drawable drawableScaled = new BitmapDrawable(context.getResources(), bitmap);

我该如何对一个整数数组的图像执行此操作? - Sereen Shalby
@SereenShalby 在回答中的编辑 - Pararth
R.drawable.image 是你的 imageAdapter.mThumbIds[position]。 - Pararth

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