何时附加和分离视图?

When are views attached and detached?

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

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

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

更新更多我想要得到的例子:

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

编辑:摘要:

来自官方文档:

An activity is a single, focused thing that the user can do. Almost all activities interact with the user...

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

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

But does that mean that the view (if it exists) must be tied to the activity only within the onCreate() method?

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

onCreate() -> onStart() -> onResume() // They get called consecutively

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

So why not inflate and attach the activity in onResume() and do all the initializations there?

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

What happens when an opaque view comes up and the Activity is now in the background but still running (like an incoming phone call or opening another activity)?

现在发生以下回调:

onPause() -> onStop()

当你搬回原来的时候activity

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

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

But what happens to the layout itself when an Activity is in the background. Is the layout still attached?

是的,确实如此。如果另一个 activity 使用与原始 activity 相同的布局,那么新的 activity 有它自己的布局并且不共享布局。

What happens if the user terminates the activity by pressing the Back button?

假设没有重写 onBackPressed() 方法来实现自定义行为(在这种情况下,它有待获取),将调用 onDestroy() 并销毁 activity 并且没有关联的视图有了它。

What happens when the activity is in the background and the Android GC decides to destroy the activity and reclaim resources?

根据文档中的 activity 生命周期,将调用 onDestroy()。但这并不能保证。在这一点上,activity 和它的关联视图只是垃圾收集并且没有 connection.The 下次启动应用程序时,onCreate() 将照常调用,您只需从头开始.

What happens when I rotate my device?

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

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

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

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

  • onCreateView()
  • onViewCreated()

按以下顺序调用方法:

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

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

So when is the fragment created in the first place by the Activity?

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

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

onCreate() [Activity] -> onAttach() [Fragment] -> onCreate() [Fragment] -> onCreateView() [Fragment] -> onViewCreated() [Fragment] -> onStart() [Activity] -> onResume() [Activity] -> onActivityCreated() [Fragment]

因此,在创建 activity 的 onStart() 方法之前,首先实例化片段视图并将其附加到片段。

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

What about Nested Views, Nested Fragments, etc.?

在嵌套视图中,就像一个布局容器在另一个布局容器中一样,parent 容器的规则适用于直接的 child 容器。总是 parent 首先被初始化。因此,对于 LinearLayout 内的小部件,parent LinearLayout 首先构造,紧接着是 child。销毁此类视图时,当 parent 不复存在时,一切都会消失。我还没有阅读任何关于这可能发生的顺序的文档。 Android GC 可能有规则,但我不确定它们是否在任何地方都有记录。

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

The bottom line for nested views is that once the parent view is destroyed, it takes the child view immediately with it.

Are views measured before they are attached or after?

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

What about using addView() to add a view to a ViewGroup manually?

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

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