何时附加和分离视图? [英] When are views attached and detached?

查看:89
本文介绍了何时附加和分离视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该问题不是关于如何检测视图是否已连接或分离的问题.

This question is not about how to detect if a view is attached or detached.

通常,什么时候附加或分离视图?有生命周期图吗?

In general, when is a view attached or detached? Is there a lifecycle diagram for this?

为澄清起见,我正在寻找以下情况的答案:活动发送到背景,不透明视图置于顶部,可见性设置为GONE,视图膨胀,父项分离等.这不是详尽的列表-我只想从根本上了解附加和分离视图的工作原理.

To clarify, I'm looking for answers to what happens when: Activity sent to background, opaque view placed on top, visibility set to GONE, view inflated, parent detached, etc. This is not an exhaustive list - I just want to understand how attaching and detaching of views works, at a fundamental level.

使用我想要获得的更多示例进行更新:

Update with more examples of what I'm trying to get at:

片段与活动又如何?
嵌套视图又如何-按什么顺序附加/分离视图(父级->子级或子级->父级)?
在附加视图之前或之后测量视图吗?
手动对ViewGroup使用addView()怎么办?

What about fragments vs. activities?
What about nested views - in what order are views attached/detached (parent->child or child->parent)?
Are views measured before they are attached or after?
What about using addView() to a ViewGroup manually?

摘要:

  • 对于活动,视图附加在setContentView()中.在onDestroy()中或在用其他视图调用setContentView()时,视图是分离的.
  • 对于片段,附加视图
  • For Activities, views are attached in setContentView(). Views are detached in onDestroy() or when setContentView() is called with a different view.
  • For Fragments, views are attached after onViewCreated() finishes, and are detached after onDestroyView() finishes.
  • For ViewGroups, views are attached in addView() and detached in removeView()
  • setVisibility() does not affect the attached state of a view

推荐答案

摘自官方文档:

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

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

首先要注意的是,将活动与布局相关联并不是必须的.您可以进行没有UI(因此也没有View)的活动. Android甚至为此没有指定UI主题.

The first thing that needs to be noted is that it is not a must for activities to be associated with a layout. You can have an activity with no UI (and hence no View). Android even specifies a no UI theme for this.

继续您的问题-调用setContentView(view)时,View将附加到Activity.通常在onCreate()方法中调用此方法.通常在onCreate()方法中具有此功能的原因是因为大多数初始化都在此完成.如果视图尚未展开并附加到活动",那么如何初始化窗口小部件?因此,如果您有视图,几乎总是会在所有其他初始化之前最终在onCreate()方法内调用setContentView().

Moving on to your question - a View gets attached to an Activity at the moment you call setContentView(view). This is usually called within the onCreate() method. The reason you usually have this in the onCreate() method is because most of the initialization is done there. And how could you initialize your widgets if the view has not been inflated and attached to the Activity? Hence, if you have a view, you almost invariable end up calling setContentView() inside your onCreate() method preceding all other initialization.

但这是否意味着视图(如果存在)必须绑定到 活动只能在onCreate()方法内进行?

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

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

To answer this question, let's see what the lifecycle of an Activity looks like. You start your app:

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

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

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

The stage you are now in is where all the widgets have been initialized.

那么为什么不膨胀活动并将其附加到onResume()并执行所有 在那里初始化吗?

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

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

Of course, you could. But imagine what happens when a dialog (a partially opaque view) shows up? The Activity is now partially covered and is in the background. The onPause() method is called. The layout is still attached to the Activity at this point. You take some action and dismiss the dialog. onResume() gets called. The layout would be inflated again. All the initializations would happen again and you would lose your state. Even if you did not have much in the way of initialization, you would still be making a pretty expensive call by calling onCreate() again. And you want to avoid this in resource limited mobile devices.

出现不透明的视图并且活动"现在处于活动状态时会发生什么 后台但仍在运行(例如打来的电话或打开其他活动)?

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()

onPause() -> onStop()

当您回到原始活动

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

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

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

For the same reason as I mentioned in onPause() you do not want to inflate and attach a layout here.

但是,当活动"位于 背景.布局仍附加吗?

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

是的,非常重要.如果出现另一个活动,该活动使用与原始活动相同的布局,则新活动具有其自己的布局,并且不会共享布局.

Yes, it very much is. If another activity comes up which uses the same layout as the original activity, then the new activity has it's own layout and there is no sharing of layouts.

如果用户通过按Back(返回)来终止活动,会发生什么情况 按钮?

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

假设未重写onBackPressed()方法以实现自定义行为(在这种情况下,该方法很容易解决),则调用onDestroy()并销毁该活动,并且不再有与之关联的视图.

Assuming the onBackPressed() method is not overridden to achieve custom behavior (in which case, it is up for grabs), onDestroy() is called and the activity is destroyed and there is no View associated with it anymore.

该活动在后台运行且Android GC会发生什么 决定破坏活动并回收资源?

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

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

According to the activity lifecycle within the documentation, onDestroy() will be called. But there is no guarantee of this. At this point, the activity and it's associated view are simply garbage collected and there is no connection.The next time you start the app, onCreate() will be called as usual and you simply start from the beginning again.

旋转设备会发生什么?

What happens when I rotate my device?

Android的工作方式是实际上破坏当前活动并再次为新的布局充气,并再次从onCreate()方法开始.因此,从技术上讲,发生的是:

The way Android works is to actually destroy the current activity and inflate the new layout again and start from the onCreate() method again. So what technically happens is:

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

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

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

Because of this, you can even have a different layout and view while in landscape mode.

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

Added the relationship between activities, fragments and views A fragment represents a portion (or behavior) on the screen. A fragment can be made to occupy the full screen or you can have multiple fragments within an Activity. Fragments have their own life cycle but it is closely tied to the host activity's life cycle (and beyond the scope of this answer). Since we are specifically talking about views, I will limit this answer to two methods of interest:

  • onCreateView()
  • onViewCreated()
  • onCreateView()
  • onViewCreated()

方法按以下顺序调用:

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

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

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

You do the actual layout inflation within the onCreateView() and then you do the initializations within the onViewCreated() method. The result of the onCreateView() method is used by Android to inflate the view.

那么,活动何时首先创建片段?

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

有两种显示片段的方法-一种是将片段放在活动的xml布局中(就像任何常规小部件一样,您将使用片段类的标准包名称来代替小部件名称)或者,您也可以使用FragmentManager以编程方式进行添加(这是首选方法).

There are two ways to display fragments - one is to put them within the xml layout of the activity (just like any regular widget where instead of the widget name, you will be using the fully qualified package name of the fragment class) or you can do the addition using FragmentManager programmatically (which is the preferred method).

如果要在xml布局中定义片段,则应该知道该片段不能以编程方式删除.很难对此进行修改并将该屏幕空间重新用于其他片段.同样在这种情况下,视图将附加并绑定到活动.在这种情况下,您将在活动的onCreate()方法内增加活动的xml布局.所以现在,流程将类似于:

If you were defining the fragment within the xml layout, you should know that the fragment cannot be removed programmatically. It would be hard to modify this and reuse that screen space for other fragments. Also in this case, the view is attached and tied to the activity. In this case, you will inflate the xml layout of the Activity within the onCreate() method of the activity. So now, the flow will looks something like:

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

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

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

So first the fragment view is instantiated and attached to the fragment before the onStart() method of the activity is created.

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

If the fragment is added programmatically, if it is added within the onCreate() method, then it follows the same flow. It can be started anywhere. You simply have to substitute the life cycle of the fragment within the activity in the appropriate place. When you add fragments programmatically, while the fragment is hosted in the activity, the view is attached to the activity. When the fragment is removed from the activity, onDetach() is called and the view is no longer a part of the Activity. The resources taken by the fragment can be released.

嵌套视图,嵌套片段等如何?

What about Nested Views, Nested Fragments, etc.?

在嵌套视图中,就像一个布局容器在另一个视图中一样,父容器的规则适用于直接子容器.总是先将父级初始化.因此,对于LinearLayout内的小部件,首先构造父级LinearLayout,然后立即构造子级.销毁此类视图时,当父级不存在时一切都会消失.我尚未阅读有关可能发生这种情况的任何文档. Android GC可能有规则,但是我不确定它们是否在任何地方都有记录.

In nested views, like one layout container inside another, the rules of the parent container apply to the immediate child container. Always the parent gets initialized first. So for a widget inside a LinearLayout, the parent LinearLayout is constructed first immediately followed by the child. When destroying such views, everything goes when the parent ceases to exist. I have not read about any documentation as to an order in which this may happen. The Android GC may have rules but I am not sure if they are documented anywhere.

您也可以有嵌套的片段-在这种情况下,父片段先于子片段被初始化(这有意义吗?).当父片段不存在时,子片段也将不存在.没有父母的孩子不能存在,但是没有孩子的父母也可以存在.

You can have nested fragments too - in this case, the parent fragment gets initialized before the child fragment does (and it makes sense doesn't it?). When a parent fragment ceases to exist, the child will also cease to exist. The child cannot exist without the parent but you can have the parent without the 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()会在此之前返回零.但是您可以做的是在附加视图之前直接在视图上调用neasure()并传递MeasureSpecs(我建议您在官方文档中阅读有关此内容的更多信息)以设置一些约束.但是,此选项并非万无一失,因为它取决于父级ViewGroup强制执行其自身的约束,而这些约束具有更高的优先级.为了简单地回答您的问题,请在附加视图后对其进行衡量.

Views are measure after they are attached. Calling getMeausredWidth() or getMeasuredHeight() will return zero prior to this. But what you can do is call neasure() directly on the view before it is attached and pass MeasureSpecs (I would suggest you read up more on this in the official docs) to set some constraints. But this option is not fool proof as it depends on the parent ViewGroup enforcing it's own constraints which take higher precedence. To simply answer your question, views are measured after they are attached.

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

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

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

This is simply the same as nested views. The child exist only when they are added and this is controlled by the user. In nested views defined in layout xml, the children are inflated immediately after their parent. Here the control is more in the hands of the user. When the parent view in this case is destroyed, it takes the child view with it.

最后一点,我还要提及的是,您不应对视图使用静态句柄,因为这会导致拆解视图时令人头疼.

As a last point, I'd also like to mention that you should not use static handles for views as this would lead to a lot of headaches with the tearing down of views.

这篇关于何时附加和分离视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆