【问题标题】:BitmapFactory OutOfMemory位图工厂内存不足
【发布时间】:2013-05-17 13:47:43
【问题描述】:

大家好。

我正在尝试制作产品目录,这就是我正在做的事情:

  • 带有 ViewPager 的活动 -- 每个产品都是这个 ViewPager 中的一个片段。 -- 每个片段都有一个画廊。

我从网上下载产品数据和图像,并将图像存储到 sdcard 中。

但我的应用程序不断崩溃,这是错误

05-22 10:04:43.829: E/AndroidRuntime(12388): FATAL EXCEPTION: main
05-22 10:04:43.829: E/AndroidRuntime(12388): java.lang.OutOfMemoryError
05-22 10:04:43.829: E/AndroidRuntime(12388):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
05-22 10:04:43.829: E/AndroidRuntime(12388):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
05-22 10:04:43.829: E/AndroidRuntime(12388):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:299)
05-22 10:04:43.829: E/AndroidRuntime(12388):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:324)

我在 Gallery 的 Adapter 上的 getView 中使用 de bitmap factory,但是当我滑动 Fragments 时它崩溃了。然后我在创建主活动时更改并创建和列出,但是现在如果我关闭活动并尝试再次打开它,它会崩溃,然后如果我尝试再次打开它会正常打开。

我做错了什么?有更好的方法吗?

这是我的画廊适配器

public class ImagemAdapter extends BaseAdapter {

        private Context ctx;
        List<Bitmap> pics;

        public ImagemAdapter(Context c, List<Bitmap> pics) {
            ctx = c;
            this.pics = pics;
        }

        @Override
        public int getCount() {

            return pics.size();
        }

        @Override
        public Object getItem(int position) {
            return pics.get(position);
        }

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

        @Override
        public View getView(int position, View convertView, ViewGroup parent){
            if(convertView == null){
                int arquivoLayout = R.layout.adp_galeria;
                LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(arquivoLayout, null);
                ImageView img = ((ImageView)convertView.findViewById(R.id.imgProd));            
                img.setImageBitmap(pics.get(position));
            }
            return convertView;
        }

}

另一个奇怪的是,适配器上的 convertView 总是为 null。

编辑:

我认为问题在于位图保留在内存中。 当调用 Fragment 的 onCreateView 时,我会用我应该显示的图像填充一个 List,当调用 Fragment 的 onDestroyView 时,我会这样做:

for(int i =0; i< imagemBit.size(); i++){
    Bitmap bmp = imagemBit.get(i);
    bmp.recycle();
    bmp = null;
}
imagemBit.clear();

但是:当我再次尝试填充列表时再次调用 onCreateView(用户返回上一页)时,应用程序崩溃并出现 OutOfMemory 异常。

【问题讨论】:

  • 使用视图支架来提高性能和平滑滚动。如果图片太大,按比例缩小一样
  • convertView 始终为空时如何使用视图持有者?
  • 我理解viewholder的概念,问题是如果convertview总是返回null,那么convertview标签中的set和holder就没有意义了。

标签: android gallery


【解决方案1】:

请看this answer
我在下载和显示许多在内存中缓存的图像时遇到了同样的问题。确保不超过一定数量的图像(取决于大小)留在内存中。

【讨论】:

  • 如何从内存中释放图像?
  • 由于用于解码位图的内存是本地分配的,而不是在堆中分配的,因此 GC 释放它更复杂。幸运的是 Bitmap 有 recycle() 方法可以立即释放内存。
  • 我在 for 循环中使用 recycle() 来释放列表中的每个项目,而我正在使用 list.clear()。但仍然有 OutOfMemory 异常
  • 您编辑的问题就是我现在要写的内容:)“适配器上的 convertView 始终为空”是不好的,因为您没有使用带有位图的旧视图。您应该正确覆盖 getViewTypeCount() 和 getItemViewType() 方法。请看这个stackoverflow.com/a/5301093/2410326
  • 那是很多事情。首先是转换的不可用,其次是图片的大小(调整它的大小消耗更少的内存),第三是内存的释放
【解决方案2】:

您的应用程序在您的代码中崩溃的地方?

我认为在您关闭应用程序后,“图片”仍然保留对位图的引用,这就是 GC 不释放位图的原因。您必须在应用停止时或在创建新位图之前释放位图。

【讨论】:

  • 没错。它保留参考,因为它在尝试再次加载 bitmapfactory 时崩溃。我尝试添加很多照片,但它总是崩溃。我认为另一个问题是图像的大小。你知道如何处理大量的大图吗?
  • 您必须使用一些在后台运行的图像加载器。如果您的图片来自网络,您可以使用 android 查询:code.google.com/p/android-query/downloads/…。在这里阅读code.google.com/p/android-query/#Image_Loading。如果没有,也许这个库可以帮助你。如果没有,我推荐的概念是:使用位图数组,位图细节数组。如果它们不为空,则开始回收它们。使用 AsyncTask 根据您的位图详细信息创建位图。
  • 伙计,我在 Fragment 的 onCreateView 内使用位图数组创建并在 DestroyView 上销毁它。它在打开应用程序之前崩溃。我做错了什么?
  • 您的崩溃究竟发生在哪里?你能给我看完整的日志吗?
  • 另一件事。我认为从 getView 加载许多大图像不是一个好主意。这个方法调用了很多次,你必须小心。要检查这一点,这里:'img.setImageBitmap(pics.get(position));'而是放一些资源图像,相同的。如果它不会崩溃,那么问题在于从 getView 加载图像。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-04
  • 2013-05-08
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多