【问题标题】:When are views attached and detached?何时附加和分离视图?
【发布时间】:2015-03-12 22:16:50
【问题描述】:

这个问题不是关于如何检测视图是附加还是分离的。

一般来说,何时附加或分离视图?有生命周期图吗?

为了澄清,我正在寻找以下情况的答案:活动发送到后台,不透明视图放置在顶部,可见性设置为GONE,视图膨胀,父分离等。这不是一个详尽的列表 -我只是想从根本上了解视图的附加和分离是如何工作的。

更新我想要了解的更多示例:

片段与活动呢?
嵌套视图怎么样 - 视图附加/分离的顺序是什么(父->子或子->父)?
观看次数是在附加之前还是之后衡量的?
手动使用 addView() 到 ViewGroup 怎么样?

编辑:摘要:

  • 对于活动,视图附加在setContentView() 中。视图在 onDestroy() 中或在使用不同视图调用 setContentView() 时分离。
  • 对于 Fragments,视图附加到 after onViewCreated() finishes,并在 onDestroyView() 完成后分离。
  • 对于 ViewGroups,视图在 addView() 中附加,在 removeView() 中分离
  • setVisibility() 不会影响视图的附加状态

【问题讨论】:

    标签: android android-view


    【解决方案1】:

    来自官方文档:

    活动是用户可以做的单一的、专注的事情。几乎 所有活动都与用户交互...

    首先需要注意的是,活动与布局关联并不是必须的。你可以有一个没有 UI 的活动(因此没有视图)。 Android 甚至为此指定了无 UI 主题。

    继续您的问题 - 在您调用 setContentView(view) 时,视图会附加到 Activity。这通常在 onCreate() 方法中调用。通常在 onCreate() 方法中有这个的原因是因为大部分初始化都是在那里完成的。如果视图没有被膨胀并附加到活动,你怎么能初始化你的小部件?因此,如果您有视图,您几乎总是会在所有其他初始化之前在 onCreate() 方法中调用 setContentView()。

    但这是否意味着视图(如果存在)必须与 活动只在 onCreate() 方法内?

    要回答这个问题,让我们看看 Activity 的生命周期是什么样的。你启动你的应用程序:

    onCreate() -> onStart() -> onResume() // 它们被连续调用

    您现在所处的阶段是所有小部件都已初始化。

    那么为什么不在 onResume() 中添加和附加活动并执行所有 在那里初始化?

    当然可以。但是想象一下当一个对话框(部分不透明的视图)出现时会发生什么? Activity 现在被部分覆盖并在后台。调用 onPause() 方法。 此时布局仍附加到 Activity。 您执行一些操作并关闭对话框。 onResume() 被调用。布局将再次膨胀。所有的初始化都会再次发生,你会失去你的状态。即使你没有太多的初始化方式,你仍然会通过再次调用 onCreate() 来进行相当昂贵的调用。您希望在资源有限的移动设备中避免这种情况。

    当一个不透明的视图出现并且 Activity 现在处于 后台但仍在运行(例如来电或打开另一个活动)?

    现在发生以下回调:

    onPause() -> onStop()

    当你回到原来的活动时

    onRestart() -> onStart() -> onResume()

    出于与我在 onPause() 中提到的相同原因,您不想在此处膨胀并附加布局。

    但是当 Activity 位于 背景。布局还附上吗?

    是的,确实如此。如果出现另一个 Activity 使用与原始 Activity 相同的布局,则新 Activity 具有自己的布局,并且不会共享布局。

    如果用户通过按返回来终止活动会发生什么 按钮?

    假设 onBackPressed() 方法没有被重写以实现自定义行为(在这种情况下,它可以被抓住),onDestroy() 被调用并且活动被销毁并且不再有与之关联的视图。

    当 Activity 处于后台和 Android GC 时会发生什么 决定销毁活动并回收资源?

    根据文档中的活动生命周期,将调用 onDestroy()。但不能保证这一点。此时,Activity 及其关联的视图只是被垃圾回收,没有连接。下次启动应用程序时,onCreate() 将照常调用,您只需从头开始。

    当我旋转我的设备时会发生什么?

    Android 的工作方式实际上是销毁当前活动并再次膨胀新布局并再次从 onCreate() 方法开始。所以技术上发生的是:

    onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onResume()

    因此,您甚至可以在横向模式下拥有不同的布局和视图。

    编辑:添加活动、片段和视图之间的关系 片段代表屏幕上的一部分(或行为)。可以使一个片段占据整个屏幕,也可以在一个 Activity 中拥有多个片段。片段有自己的生命周期,但它与宿主活动的生命周期密切相关(超出了这个答案的范围)。由于我们专门讨论视图,因此我将这个答案限制为两种感兴趣的方法:

    • onCreateView()
    • onViewCreated()

    方法按以下顺序调用:

    onAttach() -> onCreate() -> onCreateView() -> onViewCreated()

    您在 onCreateView() 中进行实际的布局膨胀,然后在 onViewCreated() 方法中进行初始化。 Android 使用 onCreateView() 方法的结果来膨胀视图。

    那么 Activity 最先创建的 Fragment 是什么时候?

    有两种显示片段的方法 - 一种是将它们放在活动的 xml 布局中(就像任何常规小部件一样,您将使用片段类的完全限定包名称而不是小部件名称)或者您可以使用 FragmentManager 以编程方式进行添加(这是首选方法)。

    如果您在 xml 布局中定义片段,您应该知道无法以编程方式删除片段。很难修改它并将该屏幕空间重新用于其他片段。同样在这种情况下,视图被附加并绑定到活动。在这种情况下,您将在 Activity 的 onCreate() 方法中扩展 Activity 的 xml 布局。所以现在,流程看起来像:

    onCreate() [活动] -> onAttach() [片段] -> onCreate() [片段] -> onCreateView() [片段] -> onViewCreated() [片段] -> onStart() [Activity] -> onResume() [Activity] -> onActivityCreated() [Fragment]

    所以在创建活动的 onStart() 方法之前,首先将片段视图实例化并附加到片段。

    如果片段是通过编程方式添加的,如果它是在 onCreate() 方法中添加的,那么它遵循相同的流程。它可以在任何地方启动。您只需在适当的位置替换活动中片段的生命周期。当您以编程方式添加片段时,当片段托管在活动中时,视图将附加到活动。当从 Activity 中移除 Fragment 时,会调用 onDetach() 并且视图不再是 Activity 的一部分。可以释放分片占用的资源。

    嵌套视图、嵌套片段等呢?

    在嵌套视图中,就像一个布局容器位于另一个容器中一样,父容器的规则适用于直接子容器。总是先初始化父级。因此,对于 LinearLayout 中的小部件,首先构造父 LinearLayout,然后紧跟其后的是子级。当破坏这样的观点时,当父母不再存在时,一切都会过去。我还没有阅读任何有关可能发生这种情况的顺序的文档。 Android GC 可能有规则,但我不确定它们是否记录在任何地方。

    你也可以有嵌套的片段——在这种情况下,父片段在子片段之前被初始化(这很有意义不是吗?)。当父片段不复存在时,子片段也将不复存在。没有父母,孩子就无法存在,但没有孩子,您可以拥有父母。

    嵌套视图的底线是,一旦父视图 销毁时,它会立即使用子视图。

    视图是在附加之前还是之后衡量的?

    视图是在附加后测量的。在此之前调用 getMeausredWidth() 或 getMeasuredHeight() 将返回零。但是您可以做的是在附加视图之前直接在视图上调用 neasure() 并传递 MeasureSpecs(我建议您在官方文档中阅读更多关于此的内容)以设置一些约束。但是这个选项并不是万无一失的,因为它依赖于父 ViewGroup 执行它自己的约束,这些约束具有更高的优先级。为了简单地回答您的问题,视图是在附加后测量的。

    使用 addView() 手动将视图添加到 ViewGroup 怎么样?

    这与嵌套视图完全相同。子项仅在添加时才存在,并且由用户控制。在布局 xml 中定义的嵌套视图中,子级在其父级之后立即膨胀。在这里,控制权更多地掌握在用户手中。在这种情况下,当父视图被销毁时,它会带上子视图。

    作为最后一点,我还想提一下,您不应该对视图使用静态句柄,因为这会导致视图的拆除带来很多麻烦。

    【讨论】:

    • 谢谢,您的回答对活动很有帮助,但我想知道的远不止这些。碎片呢?嵌套视图怎么样 - 附加视图的顺序是什么(父->子或子->父)?是在附加视图之前还是之后测量视图?对 ViewGroup 使用 addView() 怎么样?我会用更多细节更新问题。
    • 好的..我在答案中添加了更多内容以回答您的其他问题。让我知道这是否有帮助,或者您有什么想解决的问题。
    • 很好的答案,谢谢。我唯一的另一个问题是可见性变化,但从你的回答看来,可见性变化不会影响它
    • 没错。更改可见性不会删除元素本身。
    猜你喜欢
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 2015-01-03
    相关资源
    最近更新 更多