保留的片段,存在 UI 和内存泄漏



我已经读到,对呈现UI的片段.setOnRetainInstance(true)设置可能会导致内存泄漏。

有人可以解释一下为什么以及如何发生这种情况吗?我在任何地方都没有找到详细的解释。

在具有 UI 的Fragment中,您通常会保存一些View作为实例状态以加快访问速度。例如,指向EditText的链接,因此您不必一直findViewById它。

问题是View保留对Activity上下文的引用。现在,如果您保留View则还会保留对该上下文的引用。

如果上下文仍然有效,但典型的保留情况是重新启动活动,则没有问题。例如,通常用于屏幕旋转。活动重新创建将创建新上下文,而旧上下文旨在进行垃圾回收。但是现在不能对其进行垃圾回收,因为您的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中对 UI 的所有引用。重用Fragment实例后,系统将要求您在onCreateView上创建新的 UI。在onDestroyView之后保留UI也没有意义。不会使用 UI。

此示例中的修复只是将onDestroyView更改为

@Override
public void onDestroyView() {
super.onDestroyView();
mLeak = null; // now cleaning up!
}

除了保留对View的引用外,您显然不应该保留对Activity的引用(例如,来自onAttach-onDetach上干净)或任何Context(除非它是Application上下文)。

setRetainInstance(true)用于在活动重新创建期间保留动态片段的实例,例如屏幕旋转或其他配置更改。这并不意味着片段将被系统永久保留。

当活动因其他原因终止时,例如用户完成活动(即按回),片段应符合垃圾回收条件。

保留与活动耦合的某些对象时要小心。

警告:虽然可以返回任何对象,但切勿传递绑定到活动的对象,例如可绘制对象、适配器视图或与上下文关联的任何其他对象。如果这样做,它将泄漏原始活动实例的所有视图和资源。(泄漏资源意味着您的应用程序会保留它们,并且无法对其进行垃圾回收,因此可能会丢失大量内存。

http://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject

"setRetainInstance" 用于在重新创建活动时维护片段的状态。 根据官方文档:如果我们使用 "setRetainInstance",片段生命周期的 2 个方法将不会执行(onCreate、onDestroy)。 但是,片段中包含的视图将被重新创建,这是因为生命周期将从"onCreateView"执行。 在这些情况下,如果我们在"onSaveInstanceState"中保存了一些数据,我们应该在"onActivityCreated"而不是"onCreate"中请求它。

官方信息:https://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(布尔值)

更多信息: https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/en

你可以覆盖onDestroy()并调用垃圾回收器。

@Override
public void onDestroy() {
super.onDestroy();
System.gc();
System.gc();
}

最新更新