【发布时间】:2015-04-13 13:12:48
【问题描述】:
问题:
我有一个 Android 应用程序,它允许用户浏览到用户的个人资料 ViewProfileFragment。在ViewProfileFragment 内,用户可以单击一张图片,将他带到StoryViewFragment,其中会显示各种用户的照片。可以单击用户个人资料照片,将他们带到具有新用户个人资料的ViewProfileFragment 的另一个实例。如果用户反复单击用户的个人资料,单击将他们带到画廊的图像,然后单击另一个个人资料,这些片段会迅速堆积在内存中,从而导致可怕的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 适配器中的数据,“清空”变量等),以便当片段不是活动片段并推送到backstack 将释放更多内存。但我释放资源的努力只是部分成功。根据 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) 我是否忽略了一种允许 Fragment 保留在后台堆栈上但也释放其资源的方法,以便 .replace(fragment) 的循环不会占用我所有的内存?
2) 当预期可以将大量 Fragment 加载到 backstack 时,“最佳实践”是什么?开发人员如何正确处理这种情况? (或者我的应用程序中的逻辑是否存在固有缺陷,而我只是做错了?)
我们将不胜感激任何帮助集思广益的解决方案。
【问题讨论】:
-
你在使用fragment的onPause方法吗?developer.android.com/reference/android/app/…我认为你应该在fragment的onPause方法上释放所有与fragment相关的位图资源。为了提高速度,特别是如果您的图像是从 Internet 加载的,请实施图像缓存。您可以使用Universal Image Loader 或实现您自己的。
-
是的,
<currentFragment>.onPause()在发出.replace(new_fragment)时被命中。我不认为图像是我的问题,因为我在onPause()方法中调用listAdapter.clear()删除任何图像数据。这些是使用 Pico 加载的。 -
AFAIK,
listAdapter.clear()不会释放与整个片段相关的位图资源......至少所有这些资源。它只会删除列表中的所有元素。 -
我编辑了我的问题以显示我在
onPause方法中的内容,以帮助清除位图(通过调用setImageBitmap(null)并在listview 适配器上调用.clear()。还有其他/更好的方法吗释放位图? -
看看this。我认为您已经在遵循这些步骤,但以防万一。
标签: android android-fragments memory-leaks out-of-memory