安卓幻灯片导致内存泄漏

3
我希望在Android上做一个全屏幕图片幻灯片,没有缩略图(如在画廊中),没有缩放,没有捏合。只有左/右滑动以从一张图片移动到另一张。

图片保存在数据文件夹中,共约2000张。

我使用全屏ViewPager来显示图片。当然,我无法一次加载所有2000张图片,所以只有在用户划到相应的视图时才加载所需的图片。

每次用户切换到新的ViewPager位置时,我调用这段代码:

public void onNewViewToDisplay(Integer newPosition, Integer previousPosition) {
    File file = functionToGetTheCorrespondingFile(newPosition);
    Bitmap bp;
    bp = BitmapFactory.decodeFile(file.getPath());
    ((ImageView)imageAdapter.views.get(newPosition)).setImageBitmap(bp);
    if (previousPosition != null && previousPosition != newPosition) {
        BitmapDrawable bitmapDrawable = 
            ((BitmapDrawable)((ImageView)imageAdapter.views.get(previousPosition)).getDrawable());
        // Set the previous imageView to empty view
        ((ImageView) imageAdapter.views.get(previousPosition)).setImageResource(0);
        // Then free previous bitmap memory
        if (bitmapDrawable != null && bitmapDrawable.getBitmap() != null) {
            bitmapDrawable.getBitmap().recycle();
        }
    }
}

因此,我希望我的代码始终释放先前显示的图像视图所使用的内存。但是当我查看我的内存占用情况时

enter image description here

导致了内存泄漏。我做错了什么?


生成一个hprof文件并查找哪些对象在增加。这将告诉您哪些对象存在泄漏,并帮助您找到答案。 - Gabe Sechan
使用Glide或Picasso库。 - Somasundaram Mahesh
我尝试使用Glide加载imageView,出现了完全相同的问题。 - alexislg
据我所知,Glide和Picaso只允许我们点击缩略图查看相册。这不是我想要的。我只想要全屏图片,没有缩放、没有缩略图,只能左右滑动。用户可以在磁盘上的2000张图片中进行滑动。 - alexislg
@GabeSechan 感谢您的建议。我不知道如何解释这些结果... 对我来说,结论是位图正在使用所有堆。 hprof 截图:http://gangs-of-mafia.com/hprof.png alloc 截图:http://gangs-of-mafia.com/alloc.png(注:我现在使用 Picasso 但存在内存泄漏问题) - alexislg
2个回答

0

你的方法不够高效,因为每次用户滑动时都会创建一个位图。

你应该使用LruCache来存储位图,这样就不必重新创建已经解码过的位图了。


你不需要这样做,你只需将已解码的位图添加到缓存中,这样如果用户向后滑动,你就不需要重新创建它们。 - Amir Horev
好的,但如果用户滑动2000次呢?那么它就会耗尽内存。 - alexislg
如果用户滑动了2000次,那就是挑战伙计,你期望什么呢? 你应该在此过程中付出一些努力,并检查可用内存并进行维护。 - Amir Horev
是的,保持可用内存,让用户在浏览图片库时流畅体验正是我想要的。问题是如何实现呢?我尝试使用bitmap.recycle但没有效果。 - alexislg

0

好的,我找到了为什么会出现这些内存泄漏的原因。这是因为我在我的PagerAdapter中引用了views

你需要没有对views的引用,并像这样实现destroyItem

public void destroyItem (ViewGroup container, int position, Object object)
{
    ((ImageView)object).setImageResource(0);
    BitmapDrawable bmd = (BitmapDrawable) ((ImageView) object).getDrawable();
    if (bmd != null) bmd.getBitmap().recycle();
    View view = (View)object;
    ((ViewPager) container).removeView(view);
    view = null;
}

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