为什么需要Fragment?

在官方文档的翻译中,Fragment译为片段。那么它是谁的片段?当然是Activity的,其目的在于解决如下几个问题:

  • 将臃肿的Activity类分解为小的Fragment
  • 修复老版本中LocalActivityManager所带来的问题
  • 封装导航状态,如Activity本地回退栈和可管理的对话框(DialogFragment)
  • 分离主从式UI(Master/Detail)

Fragment的功能

  • 生命周期
  • 回退栈管理
  • 配置改变时保留实例
  • FragmentManager的状态管理
  • 管理一个视图
  • 在xml布局中使用<fragment>

如何高效使用Fragment

尽管在布局中可以使用<fragment>标签,但并不能将其等效为View。从它所位于的抽象层级上而言其等效于Activity,是位于View之上的,其中Android包之间的抽象层级如下所示:

    高层级      |       android.app
               |       android.widget
    低层级      |       android.view
               v       android.content

尽管AOSP中的代码可能并非严格遵循这一规则,但大体上如此。Fragment依赖于View的界面绘制与事件响应,但View对Fragment一无所知,Fragment拥有View之外的关于生命周期的知识,可以协调View之间的协作。

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的生命周期回调的一般顺序如下所示:

生命周期回调描述
onInflate
onAttach
onAttachFragment
onCreate
onCreateView
onActivityCreated
onStart
onResume
onStop
onDestoryView
onDestory
onDetach

DialogFragment

show()

    /**
     * Display the dialog, adding the fragment to the given FragmentManager.  This
     * is a convenience for explicitly creating a transaction, adding the
     * fragment to it with the given tag, and {@link FragmentTransaction#commit() committing} it.
     * This does <em>not</em> add the transaction to the fragment back stack.  When the fragment
     * is dismissed, a new transaction will be executed to remove it from
     * the activity.
     * @param manager The FragmentManager this fragment will be added to.
     * @param tag The tag for this fragment, as per
     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
     */
    public void show(FragmentManager manager, String tag) {
        mDismissed = false;
        mShownByMe = true;
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commit();
    }

    /**
     * Display the dialog, adding the fragment using an existing transaction
     * and then {@link FragmentTransaction#commit() committing} the transaction.
     * @param transaction An existing transaction in which to add the fragment.
     * @param tag The tag for this fragment, as per
     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
     * @return Returns the identifier of the committed transaction, as per
     * {@link FragmentTransaction#commit() FragmentTransaction.commit()}.
     */
    public int show(FragmentTransaction transaction, String tag) {
        mDismissed = false;
        mShownByMe = true;
        transaction.add(this, tag);
        mViewDestroyed = false;
        mBackStackId = transaction.commit();
        return mBackStackId;
    }

展示对话框,这里将fragment添加到FragmentManager中。

dimiss()

    /**
     * Dismiss the fragment and its dialog.  If the fragment was added to the
     * back stack, all back stack state up to and including this entry will
     * be popped.  Otherwise, a new transaction will be committed to remove
     * the fragment.
     */
    public void dismiss() {
        dismissInternal(false);
    }

    void dismissInternal(boolean allowStateLoss) {
        if (mDismissed) {
            return;
        }
        mDismissed = true;
        mShownByMe = false;
        if (mDialog != null) {
            mDialog.dismiss();
        }
        mViewDestroyed = true;
        if (mBackStackId >= 0) {
            getFragmentManager().popBackStack(mBackStackId,
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
            mBackStackId = -1;
        } else {
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.remove(this);
            if (allowStateLoss) {
                ft.commitAllowingStateLoss();
            } else {
                ft.commit();
            }
        }
    }

这里会将fragment从回退栈中弹出,或者从FragmentManager中移除。这里fragment会走完剩余的全部生命周期。

Fragment事务

commit()

commitNow()

executePendingTransactions()

参考: