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

时间:2013-09-05 13:03:15

标签: android view android-fragments reusability

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

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等等。现在我开始在简单的活动中使用我的片段,如果且仅当我将片段添加到backstack时,由于java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

,这将失败

所以我的问题是:

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

3 个答案:

答案 0 :(得分:12)

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

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

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

不缓存视图的另一个论点是,Android不支持按片段进行视图回收。还记得ListAdapter允许重复使用这些观点吗? Android负责缓存并正确地重用这些视图。但这不是碎片的情况。

答案 1 :(得分:7)

我目前正在重复使用这样的观点:

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

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

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

答案 2 :(得分:0)

我知道这是一个老问题。但是在使用片段数月之后,我发现在使用缓存时需要注意的一点是:如果当前缓存的布局仍然有另一个片段标记,则此缓存策略将导致嵌入片段丢失一些生命周期回调。我会详细谈谈:

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

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

这就是我想要提及的。