33

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

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

4

5 回答 5

96

Fragmentwith UI 中,您经常将一些Views 保存为实例状态以加快访问速度。例如指向您的链接,EditText这样您就不必一直访问findViewById它。

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

如果上下文仍然有效但典型的保留情况是重新启动 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.
    }
}

为了摆脱这个问题,你需要清除所有对你的 UI 的引用onDestroyView。一旦Fragment实例被重用,您将被要求在onCreateView. 将 UI 保留在onDestroyView. Ui 不会被使用。

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

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

除了保留对Views 的引用之外,您显然不应该保留对Activity(例如 from onAttach- clean on onDetach)或任何Context(除非它是Application上下文)的引用。

于 2012-11-16T19:06:14.853 回答
3

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

当 Activity 因其他原因终止时,例如用户完成 Activity(即按回),Fragment 应该有资格进行垃圾回收。

于 2012-11-16T18:03:23.090 回答
3

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

注意:虽然您可以返回任何对象,但您绝不应该传递与 Activity 相关联的对象,例如DrawableAdapterView或与 Context 关联的任何其他对象。如果这样做,它将泄漏原始活动实例的所有视图和资源。(资源泄漏意味着您的应用程序会保留它们并且它们不能被垃圾收集,因此可能会丢失大量内存。)

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

于 2013-05-03T16:24:43.697 回答
0

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

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

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

于 2017-06-21T21:21:35.493 回答
-11

您可以覆盖onDestroy() 并调用垃圾收集器。

 @Override
public void onDestroy() {
    super.onDestroy();
    System.gc();
    System.gc();
}
于 2016-04-14T09:18:33.590 回答