我已经读过,在呈现UI的片段上设置.setOnRetainInstance(true)
可能会导致内存泄漏。
有人可以解释为什么以及如何发生这种情况?我没有在任何地方找到详细的解释。
答案 0 :(得分:86)
在带有UI的Fragment
中,您经常将一些View
保存为实例状态以加快访问速度。例如,指向EditText
的链接,因此您无需始终findViewById
。
问题是View
会保留对Activity
上下文的引用。现在,如果您保留View
,您还会保留对该上下文的引用。
如果上下文仍然有效但是典型的保留情况是重新启动Activity,则没有问题。例如,经常用于屏幕旋转。活动重新创建将创建新的上下文,旧的上下文旨在被垃圾收集。但它现在不能被垃圾收集,因为你的Fragment
仍然引用了旧版本。
以下示例显示了如何不这样做
public class LeakyFragment extends Fragment {
private View mLeak; // retained
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mLeak = inflater.inflate(R.layout.whatever, container, false);
return mLeak;
}
@Override
public void onDestroyView() {
super.onDestroyView();
// not cleaning up.
}
}
要解决该问题,您需要在onDestroyView
中清除对您的用户界面的所有引用。重新使用Fragment
实例后,系统会要求您在onCreateView
上创建新的用户界面。在onDestroyView
之后保留用户界面也没有意义。 Ui不会被使用。
此示例中的修复只是将onDestroyView
更改为
@Override
public void onDestroyView() {
super.onDestroyView();
mLeak = null; // now cleaning up!
}
除了保留对View
的引用之外,您显然不应该继续引用Activity
(例如来自onAttach
- 清除onDetach
)或任何Context
}(除非它是Application
上下文)。
答案 1 :(得分:3)
保留与活动相关联的某些对象时要小心。
警告:虽然您可以返回任何对象,但您永远不应传递与活动相关联的对象,例如可绘制,适配器< / strong>,查看或与上下文关联的任何其他对象。如果这样做,它将泄漏原始活动实例的所有视图和资源。 (资源泄漏意味着您的应用程序会保留它们并且不能进行垃圾回收,因此可能会丢失大量内存。)
http://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject
答案 2 :(得分:2)
setRetainInstance(true)
用于在活动重新创建期间保留动态片段的实例,例如屏幕旋转或其他配置更改。这并不意味着片段将被系统永久保留。
当活动因其他原因而终止时,例如用户完成活动(即回退),片段应该有资格进行垃圾回收。
答案 3 :(得分:0)
&#34; setRetainInstance&#34;用于在重新创建活动时维护片段的状态。 根据官方文档:如果我们使用&#34; setRetainInstance&#34;,则不会执行片段生命周期的2种方法(onCreate,onDestroy)。 但是,片段中包含的视图将被重新创建,这是因为生命周期将从&#34; onCreateView&#34;执行。 在这些情况下,如果我们在&#34; onSaveInstanceState&#34;中保存了一些数据,我们应该在&#34; onActivityCreated&#34;而不是在&#34; onCreate&#34;。
官方信息:https://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)
更多信息:https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/en
答案 4 :(得分:-10)
你可以覆盖onDestroy()
并调用垃圾收集器。
@Override
public void onDestroy() {
super.onDestroy();
System.gc();
System.gc();
}