【问题标题】:Fragment - should I reuse view in onCreateView and how should I do that?片段 - 我应该在 onCreateView 中重用视图,我应该怎么做?
【发布时间】:2023-04-02 17:26:01
【问题描述】:

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

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.

所以我的问题是:

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

【问题讨论】:

    标签: android view android-fragments reusability


    【解决方案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 或其他生命周期方法不会被调用。

      这就是我想说的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-11
        • 2018-01-16
        • 2012-09-29
        • 2017-11-22
        • 1970-01-01
        • 2018-11-30
        相关资源
        最近更新 更多