使用通用图像加载程序查看寻呼机内存不足错误

时间:2013-02-19 13:19:17

标签: android android-viewpager out-of-memory universal-image-loader

我不确定带有通用图像加载器的ViewPager是否可以/应该用作类似接口的图库,因为我在从SD卡加载图像并以全屏方式查看时遇到内存不足错误模式。无论数字是多少,它都适用于GridView,但在查看寻呼机中查看图像时,每个位图都会占用大量内存,在10个左右的图像后,它会给出内存不足错误。

我已经看到这里发布的几乎所有问题都与使用Universal Image Loader时出现内存不足错误有关,并且在每一个问题中都出现了配置错误。

我不知道我是否使用了错误的配置或者我已经浪费了很多时间而且有点卡住,任何帮助/建议都会受到赞赏。

ImageLoader的配置:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            .memoryCache(new WeakMemoryCache())
            .denyCacheImageMultipleSizesInMemory()
            .discCacheFileNameGenerator(new Md5FileNameGenerator())
            .imageDownloader(new ExtendedImageDownloader(getApplicationContext()))
            .tasksProcessingOrder(QueueProcessingType.LIFO)
//          .enableLogging() // Not necessary in common
            .build();

显示图像选项包括:

options = new DisplayImageOptions.Builder()
            .showImageForEmptyUri(R.drawable.image_for_empty_url)
            .resetViewBeforeLoading()
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .displayer(new FadeInBitmapDisplayer(300))
            .build();

我正在使用随库提供的示例项目,但这些设置也不起作用,它只是在一段时间后崩溃。我的猜测是有一个特定的回调,我必须从视图中回收不可见的位图。

编辑:我知道它的内存泄漏,不可见的视图会在它们应该被破坏时被破坏,但内存不会被释放。下面是destroyItem回调的实现,按照不同问题给出的提示,但仍然无法找到内存泄漏。

@Override
        public void destroyItem(View container, int position, Object object) {
//          ((ViewPager) container).removeView((View) object);
            Log.d("DESTROY", "destroying view at position " + position);
            View view = (View)object;
            ((ViewPager) container).removeView(view);
            view = null;
        }

7 个答案:

答案 0 :(得分:5)

它可能不是解决它的最佳实现,但它对我有用。删除ImageViews是不够的,所以我决定在'destroyItem'中回收位图:

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    View view = (View) object;
    ImageView imageView = (ImageView) view.findViewById(R.id.image);
    if (imageView != null) {
        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        bitmap.recycle();
        bitmap = null;
    }
    ((ViewPager) container).removeView(view);
    view = null;
}

当您离开活动时,这不会清除最后3个活动页面,但我希望GC能够处理它们。

答案 1 :(得分:4)

尝试应用下一个建议:

  1. 使用ImageScaleType.EXACTLY
  2. 在光盘上启用缓存(在显示选项中)。
  3. 最后尝试使用.discCacheExtraOptions(maxImageWidthForDiscCache, maxImageHeightForDiscCache, CompressFormat.PNG, 0);

答案 2 :(得分:2)

只是张贴此内容,因为在搜索UIL和OOP时Google会出现此问题。无论什么配置,我都有OOP问题,解决了我所有问题的是this示例项目中的两个类RecyclingImageViewRecyclingBitmapDrawable

答案 3 :(得分:1)

我也使用了相同的库并且有相同的错误。作为解决方案,我创建了一个sparseArray来保存photoView实例。并像这样使用它:

 private SparseArray<PhotoView> photoViewHolder;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
       ...

       photoViewHolder = new SparseArray<PhotoView>();
       ...
 }

private class GalleryPagerAdapter extends PagerAdapter {

@Override
public View instantiateItem(ViewGroup container, int position) { 

        PhotoView photoView = new PhotoView(container.getContext());

        ImageHolder holder = new ImageHolder();
        holder.position = position;
        holder.loaded = false;

        photoView.setTag(holder);
        photoViewHolder.put(position, photoView);

                    // I used LazyList loading
        loader.DisplayImage(items.get(position), photoView);

        // Now just add PhotoView to ViewPager and return it
        container.addView(photoView, LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);

        return photoView;
    }

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    photoViewHolder.remove(position);
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

}

处理viewPager的监听器:

   pager.setOnPageChangeListener(new OnPageChangeListener() { 

    @Override
    public void onPageScrollStateChanged(int position) { 

    } 

    @Override
    public void onPageScrolled(int position, float arg1, int arg2) { 

    } 

    @Override
    public void onPageSelected(int position) { 
        if(photoViewHolder.get(position) != null) {
            ImageHolder holder = (ImageHolder)photoViewHolder.get(position).getTag();
            // Do something...
        }
    } 
});

希望这会有所帮助......

答案 4 :(得分:0)

我在github问题页面使用了kutothe的实现。

答案 5 :(得分:0)

我在使用ImageView简单地将Uri设置为iv.setImageURI(Uri.fromFile(imgFile));时出现此问题 我在使用Universal Image Loader时遇到了同样的问题,我甚至在那里寻找其他的Image Loader,并找到了另一个名为“Picasso”的好的,但它也遇到了同样的问题。

那么对我有用的是使用GestureImageView并通过XML将gesture-image:recycle设置为true,并使用以下代码加载图像:

            Drawable yourDrawable = null;

            try {
                InputStream inputStream = getActivity().getContentResolver().openInputStream(Uri.fromFile(img));
                yourDrawable = Drawable.createFromStream(inputStream, Uri.fromFile(img).toString() );
                inputStream.close();
            } catch (FileNotFoundException e) {
                yourDrawable = getResources().getDrawable(R.drawable.ic_launcher);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (yourDrawable != null)
                iv.setImageDrawable(yourDrawable);

崩溃并给出OOM错误的原因是当图像不再显示在屏幕上时,位图不会被回收,因此会发生内存泄漏。

如果还有另一种方法可以在正常ImageView中回收位图,那将是一个更好的解决方案。

希望我帮助过。

答案 6 :(得分:-1)

我知道它已经很晚了,但也许我的回答可以节省一些人的时间。经过数小时和数小时的尝试解决这个问题(几乎每个答案都发现堆栈溢出)我终于用Fresco图像库解决了它。它是一个由Facebook编写的lib,它的主要目标是以有效的方式使用内存。它非常好,我的内存错误消失了。我强烈推荐使用它。

http://frescolib.org/