保留了具有UI和内存泄漏的碎片

时间:2012-11-16 17:58:19

标签: android memory-leaks android-fragments

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

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

5 个答案:

答案 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();
}