问题:
我有一个Android应用程序,允许用户浏览到用户的个人资料ViewProfileFragment
。在ViewProfileFragment
中,用户可以单击图像,跳转到StoryViewFragment
,其中会显示各种用户的照片。用户可能会单击用户个人资料照片,然后跳转到新用户个人资料的另一个实例ViewProfileFragment
。如果用户反复点击用户的个人资料,点击跳转到相册的图像,然后点击另一个个人资料,Fragment会快速堆积在内存中,导致可怕的OutOfMemoryError
。下面是我描述的流程图:
UserA 点击 Bob 的个人资料。在 Bob 的个人资料中,UserA 点击 ImageA 跳转到各种用户照片的图库(包括 Bob 的照片)。UserA 点击 Sue 的个人资料,然后点击她的一张照片,这个过程会不断重复。
UserA -> ViewProfileFragment
StoryViewFragment -> ViewProfileFragment
StoryViewFragment -> ViewProfileFragment
从典型的流程中可以看到,ViewProfileFragment
和StoryViewFragment
的实例会不断堆积在后退栈中。
相关代码
我使用以下逻辑将它们加载为片段:
//from MainActivity
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.activity_main_content_fragment, fragment, title);
ft.addToBackStack(title);
我尝试过的方法
1) 我特别使用了FragmentTransaction
replace
,以便在进行replace
时触发onPause
方法。在onPause
中,我尽可能释放了尽可能多的资源(例如清除ListView
适配器中的数据,“nulling”变量等),以便当片段不是活动片段并被推到回退栈时,会有更多的内存被释放。但我释放资源的努力只有部分成功。根据MAT的显示,仍然有很多内存被GalleryFragment
和ViewProfileFragment
占用。
2) 我还删除了对addToBackStack()的调用,但显然这会给用户带来糟糕的体验,因为他们无法返回(当用户按下返回按钮时,应用程序将关闭)。
3) 我使用MAT找到了所有占用大量空间的对象,并在onPause
(和onResume
)方法中以各种方式处理它们以释放资源,但它们仍然占用相当大的空间。
4) 我还在两个片段的onPause
中编写了一个for循环,使用以下逻辑将所有ImageViews
设置为null:
for (int i=shell.getHeaderViewCount(); i<shell.getCount(); i++) {
View h = shell.getChildAt(i);
ImageView v = (ImageView) h.findViewById(R.id.galleryImage);
if (v != null) {
v.setImageBitmap(null);
}
}
myListViewAdapter.clear()
问题
1)我是否忽略了一种方法,可以使一个片段保留在后台堆栈中,但同时释放它的资源,以便.replace(fragment)的周期不会耗尽我的所有内存?
2)当预计有很多片段加载到后台堆栈时,“最佳实践”是什么?开发人员如何正确处理这种情况?(或者我的应用逻辑本质上是有缺陷的,我只是做错了吗?)
非常感谢您提供任何有关解决此问题的想法。
onPause
方法中所做的事情,以帮助清除位图(通过调用setImageBitmap(null)
并在listview适配器上调用.clear()
)。是否有另一种更好的方法来释放位图? - Max Worgrecycle()
仍然是我发现可以解决OutOfMemoryError的唯一方法,即使在Lollipop API上也是如此。没有其他的方法有效,我已经尝试过各种各样的东西:图像加载器首选项、图像加载器库等等。就是这样。 - Drew