1. 程式人生 > >Fragment例項化,Fragment生命週期原始碼分析

Fragment例項化,Fragment生命週期原始碼分析

Fragment的例項化,Fragment的生命週期

  1. android.support.v4.app.FragmentActivity#onCreate
@Override
protected void onCreate(Bundle savedInstanceState) {
    mFragments.attachActivity(this, mContainer, null);
    // Old versions of the platform didn't do this!
    if (getLayoutInflater().getFactory() == null
) { getLayoutInflater().setFactory(this); } super.onCreate(savedInstanceState); // .... }

    這裡主要是對LayoutInflater設定了Factory(注意:在同一個Activity中使用getBaseContext和使用Activity.this通過LayoutInflater.from獲得的LayoutInflater是同一個,但是不同的Activity獲得的不是同一個),這個Factory的作用主要是用來作為hook,便於FragmentActivity通過“fragment”Tag來建立Fragment例項。
    然後設定android.app.Activity#setContentView(int) 會觸發android.view.LayoutInflater#inflate(int, android.view.ViewGroup)->android.view.LayoutInflater#createViewFromTag。
2. android.view.LayoutInflater#createViewFromTag

View view;
   if (mFactory2 != null) {
       view = mFactory2.onCreateView(parent, name, viewContext, attrs);
   } else if (mFactory != null) {
       view = mFactory.onCreateView(name, viewContext, attrs);
   } else {
       view = null;
   }

    這裡會呼叫mFactory的onCreateView方法,這裡的mFactory也就是FragmentActivity。
3. android.support.v4.app.FragmentActivity#onCreateView

@Override
public View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) {
    if (!"fragment".equals(name)) {
        return super.onCreateView(name, context, attrs);
    }

    final View v = mFragments.onCreateView(name, context, attrs);
    if (v == null) {
        return super.onCreateView(name, context, attrs);
    }
    return v;
}

    先判斷是否是“fragment”Tag,如果不是,返回super.onCreateView,父類是直接返回null,這樣會丟給LayoutInflater中自己處理。如果是“fragment”Tag,那麼會呼叫FragmentManagerImpl的onCreateView去處理。
4. android.support.v4.app.FragmentManagerImpl#onCreateView

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    /// ...
    if (fragment == null) {
        fragment = Fragment.instantiate(context, fname);
        fragment.mFromLayout = true;
        fragment.mFragmentId = id != 0 ? id : containerId;
        fragment.mContainerId = containerId;
        fragment.mTag = tag;
        fragment.mInLayout = true;
        fragment.mFragmentManager = this;
        fragment.onInflate(mActivity, attrs, fragment.mSavedFragmentState);
        addFragment(fragment, true);

    } 
    // ...
    return fragment.mView;
}

    這裡會直接呼叫Fragment.instantiate方法去構造Fragment例項。
5. android.support.v4.app.Fragment#instantiate(android.content.Context, java.lang.String, android.os.Bundle)

public static Fragment instantiate(Context context, String fname, Bundle args) {
        Class<?> clazz = sClassMap.get(fname);
        if (clazz == null) {
            // Class not found in the cache, see if it's real, and try to add it
            clazz = context.getClassLoader().loadClass(fname);
            sClassMap.put(fname, clazz);
        }
        Fragment f = (Fragment)clazz.newInstance();
        if (args != null) {
            args.setClassLoader(f.getClass().getClassLoader());
            f.mArguments = args;
        }
        return f;

}

    直接通過class.newInstance反射呼叫了Fragment的無參構造來獲得新的Fragment例項。同時在第4步最後會呼叫addFragment來把新的Fragment新增到FragmentManagerImpl中。
6. android.support.v4.app.FragmentManagerImpl#addFragment

if (moveToStateNow) {
    moveToState(fragment);
}

    這個方法核心點會去進行Fragment的狀態變換。
7. android.support.v4.app.FragmentManagerImpl#moveToState(android.support.v4.app.Fragment, int, int, int, boolean)

if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
if (f.mSavedFragmentState != null) {
    f.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
    f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
            FragmentManagerImpl.VIEW_STATE_TAG);
    f.mTarget = getFragment(f.mSavedFragmentState,
            FragmentManagerImpl.TARGET_STATE_TAG);
    if (f.mTarget != null) {
        f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
    }
    f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
            FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
    if (!f.mUserVisibleHint) {
        f.mDeferStart = true;
        if (newState > Fragment.STOPPED) {
            newState = Fragment.STOPPED;
        }
    }
}
f.mActivity = mActivity;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
        ? mParent.mChildFragmentManager : mActivity.mFragments;
f.mCalled = false;
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);
}
f.mRetaining = false;
if (f.mFromLayout) {
    // For fragments that are part of the content view
    // layout, we need to instantiate the view immediately
    // and the inflater will take care of adding it.
    f.mView = f.performCreateView(f.getLayoutInflater(
            f.mSavedFragmentState), null, f.mSavedFragmentState);
    if (f.mView != null) {
        f.mInnerView = f.mView;
        if (Build.VERSION.SDK_INT >= 11) {
            ViewCompat.setSaveFromParentEnabled(f.mView, false);
        } else {
            f.mView = NoSaveStateFrameLayout.wrap(f.mView);
        }
        if (f.mHidden) f.mView.setVisibility(View.GONE);
        f.onViewCreated(f.mView, f.mSavedFragmentState);
    } else {
        f.mInnerView = null;
    }
}

    這個方法依次呼叫了onAttach,onCreate,onCreateView,onViewCreated方法,這也就是Fragment的生命週期中比較重要的幾個方法,同時,因為這些方法都是在Activity.onCreate中進行的,所以這些方法都會在onActivityCreated之前呼叫。
8. android.support.v4.app.FragmentActivity#onStart

@Override
protected void onStart() {
    super.onStart();

    mStopped = false;
    mReallyStopped = false;
    mHandler.removeMessages(MSG_REALLY_STOPPED);

    if (!mCreated) {
        mCreated = true;
        mFragments.dispatchActivityCreated();
    }
    // ...
    mFragments.dispatchStart();
    // ...
}

    這裡會呼叫onActivityCreated和onStart方法。

以上就是Fragment建立的過程和一些生命週期的方法的呼叫順序。

結論:
1. Fragment必須有無參構造,否則無法被例項化。
2. Fragment生命週期:Activity.onCreate->Fragment.onAttach->Fragment.onCreate->Fragment.onCreateView->Fragment.onViewCreated->Activity.onStart->Fragment.onActivityCreated->Fragment.onStart