带有 UI 和内存泄漏的 Retained Fragments [英] Retained Fragments with UI and memory leaks

查看:20
本文介绍了带有 UI 和内存泄漏的 Retained Fragments的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've read that setting .setOnRetainInstance(true) on fragments presenting UI may lead to memory leaks.

有人能解释一下为什么会这样以及如何发生吗?我没有在任何地方找到详细的解释.

Could somebody please explain why and how this would happen? I didn't find a detailed explanation anywhere.

推荐答案

在带有 UI 的 Fragment 中,您经常将一些 View 保存为实例状态以加快访问速度.例如,一个指向您的 EditText 的链接,这样您就不必一直findViewById.

In a Fragment with UI you often save some Views as instance state to speed up access. For example a link to your EditText so you don't have to findViewById it all the time.

问题在于 View 保持对 Activity 上下文的引用.现在,如果您保留一个 View,您也将保留对该上下文的引用.

The problem is that a View keeps a reference to the Activity context. Now if you retain a View you also retain a reference to that context.

如果上下文仍然有效,但典型的保留情况是重新启动活动,那没有问题.例如,经常用于屏幕旋转.Activity recreation 将创建一个新的上下文,而旧的上下文将被垃圾收集.但它现在不能被垃圾回收,因为你的 Fragment 仍然引用旧的.

That is no problem if the context is still valid but the typical retain case is restarting the Activity. Very often for a screen rotation for example. Activity recreation will create a new context and old contexts are intended to be garbage collected. But it can't be garbage collected now since your Fragment still has a reference to the old one.

下面的例子展示了如何不这样做

Following example shows how not to do it

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.

To get rid of that problem, you need to clear all references to your UI in onDestroyView. Once the Fragment instance is re-used you will be asked to create a new UI on onCreateView. There is also no point in keeping the UI after onDestroyView. The Ui is not going to be used.

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

The fix in this example is just changing onDestroyView to

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

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

And besides keeping references to Views you should obviously not keep references to the Activity (e.g. from onAttach - clean on onDetach) or any Context (unless it's the Application context).

这篇关于带有 UI 和内存泄漏的 Retained Fragments的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆