Fragment(二)

Fragment 是什么
Fragment 是什么,从官网、别人博客上看到的都是他人之言,我们还是得去看源码才能得到答案。

public class Fragment implements ComponentCallbacks,
OnCreateContextMenuListener {...}

可以看到,Fragment 没有继承任何类,只是实现了这两个接口,第二个不太重要,第一个是在内存不
足时可以收到回调。
没有什么特别信息,我们还是去看看它的主要成员。

Fragment 的主要成员

static final int INITIALIZING = 0;   // Not yet created.
static final int CREATED = 1;      // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its
creation.
static final int STOPPED = 3;      // Fully created, not started.
static final int STARTED = 4;      // Created and started, not resumed.
static final int RESUMED = 5;      // Created started and resumed.
//当前 Fragment 的状态值
int mState = INITIALIZING;
//...
// True if the fragment is in the list of added fragments.
boolean mAdded;
// If set this fragment is being removed from its activity.
boolean mRemoving;
// Set to true if this fragment was instantiated from a layout file.
boolean mFromLayout;
// Set to true when the view has actually been inflated in its layout.
boolean mInLayout;
// True if this fragment has been restored from previously saved state.
boolean mRestored;
// Number of active back stack entries this fragment is in.
int mBackStackNesting;
// Set to true when the app has requested that this fragment be hidden
// from the user.
boolean mHidden;
// Set to true when the app has requested that this fragment be
deactivated.
boolean mDetached;
// If set this fragment would like its instance retained across
// configuration changes.
boolean mRetainInstance;
// If set this fragment is being retained across the current config change.
boolean mRetaining;
// If set this fragment has menu items to contribute.
boolean mHasMenu;
// Set to true to allow the fragment's menu to be shown.
boolean mMenuVisible = true;
// Used to verify that subclasses call through to super class.
boolean mCalled;

一堆标志位和状态值。然后就是关键的成员了:

// The fragment manager we are associated with. Set as soon as the
// fragment is used in a transaction; cleared after it has been removed
// from all transactions.
FragmentManagerImpl mFragmentManager;
//Fragmemt 绑定的对象,一半就是 Activity 和 Fragment
FragmentHostCallback mHost;
//管理子 Fragment
FragmentManagerImpl mChildFragmentManager;
// For use when restoring fragment state and descendant fragments are
retained.
// This state is set by FragmentState.instantiate and cleared in onCreate.
FragmentManagerNonConfig mChildNonConfig;
//如果这个 Fragment 绑定的是另一个 Fragment,就需要设置这个值
Fragment mParentFragment;
//容器 Fragment 的ID
int mFragmentId;
//容器 View 的ID
int mContainerId;
//父布局
ViewGroup mContainer;
//当前 Fragment 的布局
View mView;
//真正保存状态的内部布局
View mInnerView;

看到这里,结合前面的,我们就清晰了一个 Fragment 的创建、添加过程:
在  onCreateView() 中返回一个 布局,然后在 FragmentManager 中拿到这个布局,添加到要绑定容
器(Activity/Fragment)的 ViewGroup 中,然后设置相应的状态值。

生命周期方法
Fragment 的生命周期大家都清楚,官方提供了一张很清晰的图:

总共 11 个方法,这里我们看一下各个方法的具体源码。
1. onAttach(Context)

@CallSuper
public void onAttach(Context context) {
  mCalled = true;
  final Activity hostActivity = mHost == null ? null :
mHost.getActivity();
  if (hostActivity != null) {
   mCalled = false;
    onAttach(hostActivity);
 }
}
@Deprecated
@CallSuper
public void onAttach(Activity activity) {
  mCalled = true;
}

onAttach() 是一个 Fragment 和它的 Context 关联时第一个调用的方法,这里我们可以获得对应的
Context 或者  Activity ,可以看到这里拿到的 Activity 是  mHost.getActivity() ,后面我们介绍
FragmentManager 时介绍这个方法。

2. onCreate(Bundle)

public void onCreate(@Nullable Bundle savedInstanceState) {
  mCalled = true;
  restoreChildFragmentState(savedInstanceState);
  if (mChildFragmentManager != null
      && !mChildFragmentManager.isStateAtLeast(Fragment.CREATED)) {
    mChildFragmentManager.dispatchCreate();
 }
}
void restoreChildFragmentState(@Nullable Bundle savedInstanceState) {
  if (savedInstanceState != null) {
    Parcelable p = savedInstanceState.getParcelable(
        FragmentActivity.FRAGMENTS_TAG);
    if (p != null) {
      if (mChildFragmentManager == null) {
        instantiateChildFragmentManager();
     }
      mChildFragmentManager.restoreAllState(p, mChildNonConfig);
      mChildNonConfig = null;
      mChildFragmentManager.dispatchCreate();
   }
 }
}

onCreate() 在  onAttach() 后调用,用于做一些初始化操作。
需要注意的是,Fragment 的  onCreate() 调用时关联的 Activity 可能还没创建好,所以这里不要有依
赖外部 Activity 布局的操作。如果有依赖 Activity 的操作,可以放在  onActivityCreate() 中。
从上面的代码还可以看到,如果是从旧状态中恢复,会执行子 Fragment 状态的恢复,此外还在
onCreate() 中调用了子 Fragment 管理者的创建。

3. onCreateView(LayoutInflater, ViewGroup, Bundle)

@Nullable
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup
container,
    @Nullable Bundle savedInstanceState) {
  return null;
}

在  onCreate() 后就会执行  onCreatView() ,这个方法返回一个 View,默认返回为 null。
当我们需要在 Fragment 中显示布局时,需要重写这个方法,返回要显示的布局。
后面布局销毁时就会调用  onDestroyView() 。
3.1. onViewCreated

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
}

onViewCreate() 不是生命周期中的方法,但是却很有用。
它会在  onCreateView() 返回后立即执行,参数中的 view 就是之前创建的 View,因此我们可以在
onViewCreate() 中进行布局的初始化,比如这样:

@Override
public void onViewCreated(final View view, @Nullable final Bundle
savedInstanceState) {
  if (view == null) {
    return;
 }
  mTextView = (TextView) view.findViewById(R.id.tv_content);
  mBtnSwitchChild = (Button) view.findViewById(R.id.btn_switch_child);
  Bundle arguments = getArguments();
  if (arguments != null && mTextView != null &&
!TextUtils.isEmpty(arguments.getString(KEY_TITLE))) {
    mTextView.setText(arguments.getString(KEY_TITLE));
 }
  mBtnSwitchChild.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(final View v) {
      //...
 });
}

4. onActivityCreated(Bundle)

@CallSuper
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  mCalled = true;
}

onActivityCreated() 会在 Fragment 关联的 Activity 创建好、Fragment 的布局结构初始化完成后
调用。
可以在这个方法里做些和布局、状态恢复有关的操作。
4.1 onViewStateRestored(Bundle)

@CallSuper
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
  mCalled = true;
}

onViewStateRestored() 方法会在  onActivityCreated() 结束后调用,用于一个 Fragment 在从
旧的状态恢复时,获取状态  saveInstanceState 恢复状态,比如恢复一个 check box 的状态。
经过这四步,Fragment 创建完成,同步于 Activity 的创建过程。

5. onStart()

@CallSuper
public void onStart() {
  mCalled = true;
  if (!mLoadersStarted) {
    mLoadersStarted = true;
    if (!mCheckedForLoaderManager) {
      mCheckedForLoaderManager = true;
      mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted,
false);
   }
    if (mLoaderManager != null) {
      mLoaderManager.doStart();
   }
 }
}

onStart() 当 Fragment 可见时调用,同步于 Activity 的  onStart() 。
6. onResume()

@CallSuper
public void onResume() {
  mCalled = true;
}

onResume() 当 Fragment 可见并且可以与用户交互时调用。
它和 Activity 的  onResume() 同步。
7. onPause()

@CallSuper
public void onPause() {
  mCalled = true;
}

onPause() 当 Fragment 不再可见时调用。
也和 Activity 的  onPause() 同步。
8. onStop()

@CallSuper
public void onStop() {
  mCalled = true;
}

onStop() 当 Fragment 不再启动时调用,和  Activity.onStop() 一致。

9. onDestroyView()

@CallSuper
public void onDestroyView() {
  mCalled = true;
}

当  onCreateView() 返回的布局(不论是不是 null)从 Fragment 中解除绑定时调用
onDestroyView() 。
下次 Fragment 展示时,会重新创建布局。
10. onDestroy()

@CallSuper
public void onDestroy() {
  mCalled = true;
  //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" +
mCheckedForLoaderManager
  //    + " mLoaderManager=" + mLoaderManager);
  if (!mCheckedForLoaderManager) {
    mCheckedForLoaderManager = true;
    mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted,
false);
 }
  if (mLoaderManager != null) {
    mLoaderManager.doDestroy();
 }
}

当 Fragment 不再使用时会调用  onDestroy() ,它是一个 Fragment 生命周期的倒数第二步。
可以看到这里,调用了  mLoaderManager.doDestroy() ,后面介绍它。
11. onDetach()

@CallSuper
public void onDetach() {
  mCalled = true;
}

Fragment 生命周期的最后一个方法,当 Fragment 不再和一个 Activity 绑定时调用。
Fragment 的  onDestroyView() ,  onDestroy() ,  onDetach() 三个对应 Activity 的  onDestroyed()方法。

总结
OK,看完这篇文章,相信对开头提出的问题你已经有了答案,这里再总结一下。
Fragment、FragmentManager、
FragmentTransaction 关系

Fragment

其实是对 View 的封装,它持有 view, containerView, fragmentManager,
childFragmentManager 等信息
FragmentManager
是一个抽象类,它定义了对一个 Activity/Fragment 中 添加进来的 Fragment 列表、
Fragment 回退栈的操作、管理方法
还定义了获取事务对象的方法
具体实现在 FragmentImpl 中
FragmentTransaction
定义了对 Fragment 添加、替换、隐藏等操作,还有四种提交方法
具体实现是在 BackStackRecord 中

Fragment 如何实现布局的添加替换

通过获得当前 Activity/Fragment 的 FragmentManager/ChildFragmentManager,进而拿到事务的实
现类 BackStackRecord,它将目标 Fragment 构造成 Ops(包装Fragment 和状态信息),然后提交给
FragmentManager 处理。
如果是异步提交,就通过 Handler 发送 Runnable 任务,FragmentManager 拿到任务后,先处理 Ops
状态,然后调用  moveToState() 方法根据状态调用 Fragment 对应的生命周期方法,从而达到
Fragment 的添加、布局的替换隐藏等。
下面这张图从下往上看就是一个 Fragment 创建经历的方法:

嵌套 Fragment 的原理
也比较简单,Fragment 内部有一个 childFragmentManager,通过它管理子 Fragment。
在添加子 Fragment 时,把子 Fragment 的布局 add 到父 Fragment 即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值