【问题标题】:Difference between onCreateView and onViewCreated in FragmentFragment中onCreateView和onViewCreated的区别
【发布时间】:2014-09-26 22:49:27
【问题描述】:

这两种方法的本质区别是什么?当我创建一个 TextView 时,我应该使用其中一个来提高性能吗?

编辑: 有什么区别

onCreateView() {
  root = some view
  View v = new View(some context);
  root.add(v);
  return root;
}


onViewCreated() {
  View v = new View(some context);
  getView().add(v);
}

【问题讨论】:

  • 我添加了一个编辑来解释我的困惑。如果一种方法紧随其后,为什么会有两种?不能像上面那样在一个方法中完成所有视图的创建吗?
  • 如果你必须用谷歌搜索和猜测,可能存在命名错误的方法。

标签: android android-layout android-fragments


【解决方案1】:

我们在onCreateView 中面临一些初始化视图的崩溃。

您应该在onCreateView 中扩展您的布局,但不应该在onCreateView 中使用findViewById 初始化其他视图。

因为有时视图没有正确初始化。所以总是在onViewCreated中使用findViewById(当视图完全创建时),它也将视图作为参数传递。

onViewCreated 是确保视图已完全创建。

onViewCreated android 文档

onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle) 返回后立即调用,但在任何保存的状态恢复到视图之前。一旦子类知道他们的视图层次结构已经完全创建,这给了子类一个初始化自己的机会。然而,片段的视图层次结构此时并未附加到其父级。

【讨论】:

  • 谢谢。我也遇到了这个问题并使用了 component.post(...) 方法等到它显示出来。可能会在onViewCreated中进行findViewById等初始化。
  • 这段文字是从哪里引用的?我在官方文档中找不到。
  • 能否请您在此处引用的声明中发布来自开发者网站的参考资料?
  • 这实际上是不正确的。您可以在 onCreateView 中找到一个视图,但只有在您对其进行膨胀之后,并且只能从您已经膨胀的视图中找到。 Fragment.findViewById() 不安全,但 View.findViewById() 如果您已经膨胀了片段视图,则它是安全的。
【解决方案2】:

onViewCreatedonCreateView(你初始化和创建所有对象的方法,包括你的TextView)之后立即被调用,所以这不是性能问题。

来自开发者网站:

onViewCreated(View view, Bundle savedInstanceState)

在 onCreateView(LayoutInflater, ViewGroup, Bundle) 返回后立即调用,但在任何保存的状态恢复到视图之前。一旦子类知道他们的视图层次结构已经完全创建,这给了子类一个初始化自己的机会。然而,片段的视图层次结构此时并未附加到其父级。

来源:Fragment#onViewCreated

【讨论】:

    【解决方案3】:

    最好将子视图分配给onViewCreated 中的字段。这是因为框架会自动为您执行 null 检查,以确保您的 Fragment 的视图层次结构已正确创建和扩展(如果使用 XML 布局文件)。

    代码 sn-p 来自:FragmentManger.java

    // This calls onCreateView()
    f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);
    
    // Null check avoids possible NPEs in onViewCreated
    // It's also safe to call getView() during or after onViewCreated()
    if (f.mView != null) {
        f.mView.setSaveFromParentEnabled(false);
        if (f.mHidden) f.mView.setVisibility(View.GONE);
        f.onViewCreated(f.mView, f.mSavedFragmentState);
    }
    

    【讨论】:

    • 它还将任何初始化逻辑与视图层次结构膨胀/创建逻辑分开
    • 这很有趣,您是否有任何其他资源说明为什么这种方法更好?这是否意味着每个 onCreateView 方法都应该只包含一个“return inflater.inflate(R.layout.layout_file, container, false);”和 onviewcreated 应该有所有“findViewById”方法吗?这会带来什么性能提升?它会使过渡更快吗?
    • 回答您的第一个问题,onCreateView 用于创建片段的视图层次结构。这可以通过 XML 膨胀或动态创建(即,以编程方式创建 Java 视图)。所以你可能根本不会打电话给inflate。但是如果片段需要一个 UI 元素,你应该返回一些父视图。否则返回null
    • 根本没有性能提升。查看FragmentManagerperformCreateView 的片段代码,它调用onCreateView github.com/android/platform_frameworks_base/blob/…,除了onViewCreated 生命周期回调,你可以保证一些事情:
    • 1.如果片段已动态添加到其父活动,则视图层次结构将附加到容器。 2. 您可以安全地进行视图查找,而不必担心 NPE。 3. 我对动画不是很熟悉,但是片段转换已经开始了(即发送到 UI 线程消息队列)。
    【解决方案4】:

    onCreateView() 是活动的 onCreate() 的 Fragment 等效项,并在视图创建期间运行。
    onViewCreated() 在视图创建之后运行.

    should I use one over the other for performance? 。没有证据表明性能有所提升。

    Fragments 中实际上也有一个onCreate() 方法,但它很少使用(我确实从不使用它,也没有找到一个好的用例)。

    我总是在 Fragments 中使用onCreateView() 来代替onCreate()
    我对此很满意。

    【讨论】:

    • @npace,为什么?我也认为onCreateView相当于Activity的onCreate
    • @CoolMind 好吧,nPace 并没有完全错,因为 Framents 中也有一个 onCreate() 方法。但它从未使用过(或者,至少,我确实从未使用过它)。我总是在 Fragments 中使用onCreateView() 作为替代品。
    • @Rotwang,同意你的看法!有些教程使用onCreate来放setHasOptionsMenu(true),但我觉得放在onCreateView或者onViewCreated会更好。
    • @CoolMind 我完全同意。也许我在回答中使用了错误的词。
    • @Rotwang,你说得对。第一次使用fragments的时候,也不知道为什么不使用onCreate。
    【解决方案5】:

    onCreateView 返回膨胀的视图。 OnViewCreatedonCreateView 之后被调用,并且 get 具有膨胀视图的参数。它的返回类型是void

    【讨论】:

    • 我添加了一个编辑来解释我的困惑。如果一种方法紧随其后,为什么会有两种?不能像上面那样在一个方法中完成所有视图的创建吗?
    • onCreateView 应该很快返回。例如,OnViewCreate 可用于执行初始化工作。正如我所说,onViewCreated 将您在 onCreateView 中膨胀的视图作为参数。所以你可以避免getView调用
    【解决方案6】:

    The docs for Fragment.onCreateView() 现在说:

    建议只在此方法中对布局进行膨胀,并将对返回的 View 进行操作的逻辑移动到 onViewCreated(View, Bundle) 中。

    我们不需要理解为什么;我们只需要按照文档所说的去做,但是知道为什么存在这个建议会很有趣。我最好的猜测是separation of concern,但恕我直言,这使它变得比它必须的要复杂一些。

    【讨论】:

    • 如果原因是关注点分离,那为什么Activity会在onCreate()中膨胀setContentView()中的布局?
    • @MinhNghĩa 好点。这些问题的答案可能只是它是由不同的程序员以不同的方式设计的(在我们第一次使用 Android 几年后引入了片段),但谁知道呢。
    【解决方案7】:
    • 好的,所以如果我们要讨论onCreateView()onViewCreated()。有必要谈谈片段生命周期。有关片段生命周期的完整文档可以在 HERE 找到,我建议您阅读它,因为我们只会讨论与 onCreateView()onViewCreated() 相关的状态。

    • 片段生命周期包含 5 个状态:

    • 1) 初始化

    • 2) 已创建

    • 3) 开始

    • 4) 已恢复

    • 5) 销毁

    • 之所以需要讨论片段生命周期,是因为onCreateView()onViewCreated() 在生命周期的CREATED 状态期间都会被调用。

    • 所以当一个片段被实例化时,它会以INITIALIZED 状态开始,例如当你看到:

    CustomFragment frag1 = new CustomFragment() //`INITIALIZED` state
    CustomFragment.class                        //`INITIALIZED` state
    
    
    • .class 语法是 class literal 语法,为了简要总结,我建议阅读博客文章 HERE

    • 对于要转换到其他生命周期状态的片段,必须将其添加到 Fragment Manager

    片段管理器负责确定其片段应该处于什么状态,然后将它们移动到该状态。

    onCreateView() 和 onViewCreated() 的区别

    • 将片段添加到片段管理器后,将调用onAttach() 将片段附加到宿主活动。

    • 一旦调用onAttch(),片段就会进入CREATED 状态。正是在这种状态下,Android 系统开始创建片段的视图。这可以通过几种方式完成,例如documentation states:

    在大多数情况下,您可以使用带有@LayoutId 的片段构造函数,它会在适当的时间自动膨胀视图。您还可以覆盖 onCreateView() 以编程方式膨胀或创建片段的视图

    • 如果我们查看 documentation 对应的 onCreateView(),我们会看到:

    建议只在该方法中膨胀布局,并将对返回的View进行操作的逻辑移动到onViewCreated

    结论

    • 现在结合所有我们可以得出的结论,onCreateView()onViewCreated() 在片段生命周期的CREATED 状态期间被调用。但是,onCreateView() 首先被调用,并且应该只用于扩充片段的视图。 onViewCreated() 被称为第二个,所有与膨胀视图上的操作有关的逻辑都应该在这个方法中。

    【讨论】:

      【解决方案8】:

      我认为这些之间的主要区别是当您使用 kotlin.in onCreateView() 每次您想要访问 xml 文件中的视图时,您应该使用 findViewById但在 onViewCreated 中,您只需调用它的 id 即可访问您的视图。

      【讨论】:

      • 这是真的吗?如果我只是在代码中使用 id ,我的视图就会为空。我需要始终使用 findViewById。
      • 不,不是...... oncreate 视图实例化视图,onviewcreated 是在 oncreateview 之后和保存的状态恢复之前调用的......它更多的是片段生命周期中的时间问题
      【解决方案9】:

      我使用onViewCreated 的主要原因是因为它将任何初始化逻辑与视图层次结构膨胀/创建逻辑分开,应该放在onCreateView 中。所有其他性能特征看起来都一样。

      【讨论】:

        【解决方案10】:

        onCreateView 在片段中用于创建布局和膨胀视图。 onViewCreated 用于引用上述方法创建的视图。 最后,在 onActivityCreated 中定义动作监听器是一个好习惯。

        【讨论】:

          【解决方案11】:

          Google Documentation

          在 Fragment 超类中声明 xml 资源有一个新的解决方案

          class ExampleFragment : Fragment(R.layout.example_fragment) { }
          

          然后在onViewCreate中绑定视图

          private lateinit var binding : ExampleFragmentBinding
          
          override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
              super.onViewCreated(view, savedInstanceState)
              binding = ExampleFragmentBinding.bind(view)
          }
          

          这样你就不需要在 onCreatedView 中膨胀视图或在 onDestroy 中处理视图

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-05-09
            • 1970-01-01
            • 2015-01-29
            • 1970-01-01
            • 2013-03-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多