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


我不确定带有通用图像加载器的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;
        }

9235
2018-02-19 13:19


起源



答案:


尝试应用下一个建议:

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

4
2018-02-24 16:13



正如我上面提到的,我使用github问题链接中提到的实现使其工作。这导致了另一个错误,每当我删除一张图片时,抛出异常(非法状态异常,ImageView不再存在,不应该使用此PhotoViewAttacher)。奇怪的是,我在getItemPosition中返回POSITION_NONE,而不是最好的实现,但对我的情况来说已经足够了,不知道为什么会发生这种情况? - Faraz Hassan
对于您的新例外,请参阅附加的补丁: github.com/chrisbanes/PhotoView/pull/34 - shem
不,没有用,仍然崩溃。更改页面时的相同异常。 - Faraz Hassan
无论配置如何,Imageloader仍然给我一个带有ViewPager的OOM。我在SD卡上每个商店只加载jpg <100Ko - Damien Locque
尝试在内存中禁用缓存(在 DisplayImageOptions。 - NOSTRA


答案:


尝试应用下一个建议:

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

4
2018-02-24 16:13



正如我上面提到的,我使用github问题链接中提到的实现使其工作。这导致了另一个错误,每当我删除一张图片时,抛出异常(非法状态异常,ImageView不再存在,不应该使用此PhotoViewAttacher)。奇怪的是,我在getItemPosition中返回POSITION_NONE,而不是最好的实现,但对我的情况来说已经足够了,不知道为什么会发生这种情况? - Faraz Hassan
对于您的新例外,请参阅附加的补丁: github.com/chrisbanes/PhotoView/pull/34 - shem
不,没有用,仍然崩溃。更改页面时的相同异常。 - Faraz Hassan
无论配置如何,Imageloader仍然给我一个带有ViewPager的OOM。我在SD卡上每个商店只加载jpg <100Ko - Damien Locque
尝试在内存中禁用缓存(在 DisplayImageOptions。 - NOSTRA


它可能不是解决它的最佳实现,但它对我有用。删除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能够处理它们。


5
2018-03-12 17:31



考虑到我没有使用'ImageLoader.cacheMemory'。如果是问题。 - txuslee
还不够吗? @Override public void destroyItem(View collection, int position, Object view) { ((ViewPager) collection).removeView((View) view); } - Sazzad Hissain Khan
应该是,但还不够。回收位图解决了我的崩溃,虽然我也相信它不是一个非常正统的方法。 - txuslee
为我工作tnx .. - Isham


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


2
2018-03-26 08:10





我也使用了相同的库并且有相同的错误。作为解决方案,我创建了一个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...
        }
    } 
});

希望这可以帮助...


1
2018-03-07 13:48



不是真的:/问题仍然存在:S - Faraz Hassan
你已经完成了这一步,对吧? github.com/xeodou/PhotoView/commit/... - yahya
是的,但是没有效果,让我分享我正在做这一切的活动代码。也许你可以告诉我我做错了什么 - Faraz Hassan
哦,等待它.. - yahya
继承人代码的链接: pastie.org/private/ezvnfcdi6iicosxys1c5g - Faraz Hassan


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


0
2018-02-21 14:32



遗憾的是,链接已经消失 - Youngjae


简单地将Uri设置为时,我遇到了这个问题 ImageView 使用: iv.setImageURI(Uri.fromFile(imgFile)); 我对Universal Image Loader也有同样的问题,我甚至在那里寻找其他的Image Loaders,并找到另一个名为“毕加索“,但它也有同样的问题。

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

            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,那将是一个更好的解决方案。

希望我帮忙。


0
2017-09-10 10:29





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

http://frescolib.org/


-1
2018-01-21 18:35



答案与提出的问题无关。是的,它是一个可能有用的替代库,但不能解决这里提到的问题。 - Faraz Hassan
我知道,但是我写了这个,因为我和UIL和View Pager有同样的问题。我花了太多时间来解决这个问题,但仍然发生内存不足错误。在我实施了Fresco lib(花了我大约10分钟)后,问题再也没有发生过了。添加此lib对我的项目没有负面影响 - 您需要做的最糟糕的事情是用Fresco的自定义视图替换ImageView,这仍然很容易。我用Fresco替换了UIL,我遇到了0个问题。它易于使用,看起来更友好。这就是为什么我这么推荐它,只是测试它:) - Jesus Christ