TL;DR:
为了在Android的不同UI组件之间保持设计一致性,onCreate()
方法将在所有组件中具有类似的功能。
当将容器链接到内容时,例如将窗口链接到Activity和Activity链接到Fragment,需要进行初步检查以确定容器的状态。这就解释了在片段生命周期中使用和位置的onAttach()
的用途。
太短了,需要更长的:
答案就在原型代码中。
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
另一个例子是在Jake Wharton的ActionBarSherlock库中。
为什么你想要使用像onCreate()
这样的方法,它在activity,service中具有相同的目的。
onCreate()
旨在处理与特定上下文创建相关的问题。如果将onCreate()
用于检查其容器的状态,则没有意义。
我能想到的第二个原因是,片段被设计为独立于活动。在初始化片段之前,onAttach()
提供了一种接口来确定包含活动与片段相关的状态/类型/(对片段重要的其他细节)。
编辑:
活动存在并且具有自我维持的生命周期。
对于片段:
独立的生命周期组件(与任何其他组件相同):
基于交互的组件:
来自文档:
一个片段的生命周期流程受其宿主活动影响,每个连续的活动状态决定了片段可以接收哪些回调方法。例如,当活动已经接收到其onCreate()回调时,活动中的片段最多只会接收到onActivityCreated()回调。一旦活动达到恢复状态,你就可以自由地向活动添加和删除片段。因此,只有在活动处于恢复状态时,片段的生命周期才能独立改变。然而,当活动离开恢复状态时,片段再次被活动推动通过其生命周期。onCreate
的定义是负责创建一个片段。考虑方向的情况,您的片段可能是:
- 在不同的方向上使用不同的布局。
- 仅适用于纵向方向而不是横向方向。
- 仅在平板电脑和手机上使用。
所有这些情况都需要在从Android的角度(onCreate()
)初始化片段并填充视图之前进行检查。
还要考虑无界面片段的情况。 onAttach()
为您提供了所需的接口进行初步检查。
onAttach()
方法会将宿主Activity分配给Fragment。如果在onCreate()
之后调用它,则Fragment将没有上下文(getActivity()
将返回null
),您无法在onCreate()
方法中使用该上下文进行任何操作。
另一个适合的原因是Fragment的生命周期与Activity的生命周期类似。在Activity.onAttach()
中,Activity会附加到其父窗口。同样,在Fragment.onAttach()
中,片段会在任何其他初始化操作之前连接到其父活动。
setRetainInstance(boolean retain)
文档:void moveToState(Fragment f,
int newState,
int transit,
int transitionStyle,
boolean keepActive) {
...
f.onAttach(mActivity);
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
mActivity.onAttachFragment(f);
}
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState); // <- Here onCreate() will be called
}
...
}
情况1:未保存碎片或setRetainInstanceState(false)
应用启动。使用FragmentManager动态添加Fragment,或通过setContentView()
从XML中加载Fragment。
onAttach()
在Activity super.onCreate()
调用之后被调用——Activity已经初始化。
MainActivity﹕ call super.onCreate() before
MainActivity﹕ super.onCreate() returned
MainFragment﹕ onAttach() getActivity=com.example.MainActivity@1be4f2dd
MainFragment﹕ onCreate() getActivity=com.example.MainActivity@1be4f2dd
配置已更改。 Activity 从保存的状态重新创建片段,片段在 Activity 的super.onCreate()
调用内添加/附加:
MainActivity﹕ call super.onCreate() before
MainFragment﹕ onAttach() getActivity=com.example.MainActivity@2443d905
MainFragment﹕ onCreate() getActivity=com.example.MainActivity@2443d905
MainActivity﹕ super.onCreate() returned
案例 2: setRetainsInstanceState(true)
应用程序已启动。使用FragmentManager动态添加片段或通过setContentView()
从XML填充。与上述相同:
onAttach()
在Activitysuper.onCreate()
调用后调用- Activity已经初始化。
MainActivity﹕ call super.onCreate() before
MainActivity﹕ super.onCreate() returned
MainFragment﹕ onAttach() getActivity=com.example.MainActivity@3d54a168
MainFragment﹕ onCreate() getActivity=com.example.MainActivity@3d54a168
配置已更改。
片段onCreate()
未调用,但onAttach()
仍然被调用 - 你需要知道,托管活动已更改。但是片段已经创建,因此不会调用onCreate()
。
MainActivity﹕ call super.onCreate() before
MainFragment﹕ onAttach() getActivity=com.example.MainActivity@d7b283e
MainActivity﹕ super.onCreate() returned
onAttach()
在onCreate()
之前被调用的两个原因。
所以,片段必须首先“附加”到活动中来定义自己的视图布局。
onCreate()
被调用用于片段的初始创建。很明显,只有在创建前提条件(即一个片段必须始终嵌入在活动中,并且必须连接到其活动)满足时才会进行创建。
getActivity()
在onActivityCreated()
之前是空值,即使已经调用了接收activity
作为参数的onAttach()
方法。 - EpicPandaForce