片段 - 我应该在 onCreateView 中重用视图,我应该怎么做?

Posted

技术标签:

【中文标题】片段 - 我应该在 onCreateView 中重用视图,我应该怎么做?【英文标题】:Fragment - should I reuse view in onCreateView and how should I do that? 【发布时间】:2013-09-09 08:03:11 【问题描述】:

实际上,我总是在片段中重复使用我的视图,如下所示:

private View mView = null;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

    if (mView == null)
        mView = inflater.inflate(R.layout.view);
    return mView;

使用 viewpager 等有效。现在我也开始在简单的活动中使用我的片段,当且仅当我将片段添加到后台堆栈时,这将失败,因为java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

所以我的问题是:

可以吗,如果我检查视图父级,将其删除并添加到新父级? 或者我应该总是重新创建视图并且从不重复使用它?如果是,为什么? 是否还有其他点会导致重用视图失败?

【问题讨论】:

【参考方案1】:

也许这有助于理解行为。如果您查看FragmentManagerImpl.java,您会发现以下内容:

首先我们通过调用onCreateView()第 845 行)创建一个视图,然后我们用另一个视图包装创建的视图,它成为我们视图的父视图(第 848-849 行)。这意味着我们的视图不会成为真正容器的子视图,但它现在是包装视图的子视图。当视图从容器中移除时(第 998 行),重用问题就会发生。 FragmentManager 从容器中移除包装视图,但我们的真实视图仍然添加到父包装视图。这就是导致您遇到问题的原因。

因此,如果您将视图从其父视图中移除,它就可以工作。即使知道这一点,我也不建议在片段中重用视图,因为视图可以比片段更长寿,因为即使在片段被销毁后它们也可以用于“消失”动画。如果您当时尝试从其父视图中移除此类视图,则动画可能会被破坏。

另一个不缓存视图的论据是,android 不支持在设计上在片段中回收视图。还记得ListAdapter 允许重用视图吗? Android 负责缓存和正确重用这些视图。但片段并非如此。

【讨论】:

【参考方案2】:

我目前正在重用视图,如下所示:

if(view == null)
    view = (ViewGroup) inflater.inflate(R.layout.news_list, container, false);
 else 
    ((ViewGroup) view.getParent()).removeView(view);

return view;

我不知道这种方式是否正确,但它似乎对我有用..

注意:我使用这种方法是因为我在片段中有一个列表视图,当用户点击一个项目时,它会加载一个新片段(片段管理器使用当前列表片段替换)。然后,当用户点击后退按钮时,因为我正在重用片段的相同旧视图(使用 FM 删除时不会破坏),然后用户继续在打开详细片段视图之前的位置查看列表。

【讨论】:

嗨@edrain,您的解决方案工作正常,但即使我弹出了我的片段,它也没有从容器中删除视图。【参考方案3】:

我知道这是一个老问题。但是在使用 Fragment 几个月后,我发现在这种方式使用缓存时需要提到的一点是:如果您当前缓存的布局还有另一个 Fragment 标签,这种缓存策略会导致嵌入 Fragment 丢失一些生命周期回调。我会详细说:

1.当前片段onCreateView被第一次调用。通过像上面这样的缓存,我们将膨胀目标布局(这个布局包括一个片段标签)。 2.通过inflater.inflate这将使嵌入片段正确添加到布局中,onCreateView将被调用。 3.当前fragment需要销毁时,embed fragmentonDestroyView会被正确调用。

4.当当前片段onCreateView再次调用时,我们返回一个缓存视图,而不调用inflater.inflate。您会发现嵌入片段onCreateViewonDestroyView 或其他生命周期方法不会被调用。

这就是我想说的。

【讨论】:

以上是关于片段 - 我应该在 onCreateView 中重用视图,我应该怎么做?的主要内容,如果未能解决你的问题,请参考以下文章

多次调用片段 onCreateView

Android Java:在 onCreateView() 中返回空视图的片段

片段中的 super.onCreateView

替换未调用 onAttach、onCreate、onCreateView 等的活动中的片段

完成 onCreate 中的活动时,如何在 onCreate 之前调用我的片段的 onCreateView?

调用 onCreateView() 之前出现“找不到片段 id 的视图”错误