Android进化

Activity与Fragment怎么关联?

2019-11-14  本文已影响0人  锄禾豆

引言

通常我们在Activity的onCreate生命周期中导入如下代码:

FragmentTransaction ft = getFragmentManager().beginTransaction();//1
ft.add(R.id.fragment_area, fragment, "fragment");//2
ft.commit();

注解1:
getFragmentManager()获取的是FragmentManagerImpl 对象。final class FragmentManagerImpl extends FragmentManager。
而FragmentManager是一个抽象类。abstract class FragmentManager
getFragmentManager().beginTransaction()获取的是BackStackRecord对象

注解2:
R.id.fragment_area是setContentView的layout对应的id,一定是ViewGroup对象(后面会有说明),例如LinearLayout、FrameLayout等
fragment是Fragment的对象

关键类

frameworks/base/core/java/android/app
FragmentManager.java(FragmentManagerImpl)
BackStackRecord
Fragment

关键分析

注:8.1系统代码为例

BackStackRecord.java

ft.add(R.id.fragment_area, fragment, "fragment");

public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
        doAddOp(containerViewId, fragment, tag, OP_ADD);
        return this;
}

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
        ······
        fragment.mFragmentManager = mManager;

        if (tag != null) {
            if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
                throw new IllegalStateException("Can't change tag of fragment "
                        + fragment + ": was " + fragment.mTag
                        + " now " + tag);
            }
            fragment.mTag = tag;
        }

        if (containerViewId != 0) {
            ······
            fragment.mContainerId = fragment.mFragmentId = containerViewId;
        }

        addOp(new Op(opcmd, fragment));
    }
从这里可以看到,我们初始化了fragment的很多变量,特别是
fragment.mContainerId = fragment.mFragmentId = containerViewId;
FragmentManager.java
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
······
                switch (f.mState) {
                    ······
                    case Fragment.CREATED:
                    // This is outside the if statement below on purpose; we want this to run
                    // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
                    // * => CREATED as part of the case fallthrough above.
                    ensureInflatedFragmentView(f);

                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        if (!f.mFromLayout) {
                            ViewGroup container = null;//1
                            if (f.mContainerId != 0) {
                                if (f.mContainerId == View.NO_ID) {
                                    throwException(new IllegalArgumentException(
                                            "Cannot create fragment "
                                                    + f
                                                    + " for a container view with no id"));
                                }
                                container = mContainer.onFindViewById(f.mContainerId);//2
                                if (container == null && !f.mRestored) {
                                    String resName;
                                    try {
                                        resName = f.getResources().getResourceName(f.mContainerId);
                                    } catch (NotFoundException e) {
                                        resName = "unknown";
                                    }
                                    throwException(new IllegalArgumentException(
                                            "No view found for id 0x"
                                            + Integer.toHexString(f.mContainerId) + " ("
                                            + resName
                                            + ") for fragment " + f));
                                }
                            }
                            f.mContainer = container;
                            f.mView = f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);//3
                            if (f.mView != null) {
                                f.mView.setSaveFromParentEnabled(false);
                                if (container != null) {
                                    container.addView(f.mView);//4
                                }
                                if (f.mHidden) {
                                    f.mView.setVisibility(View.GONE);
                                }
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                        false);
                                // Only animate the view if it is visible. This is done after
                                // dispatchOnFragmentViewCreated in case visibility is changed
                                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                        && f.mContainer != null;
                            }
                        }

                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }                
   ······             
}

注解1,我们可以看到有一个ViewGroup,而ViewGroup怎么来的呢?
注解2说明了来处,跟踪代码你会知道:
container对象是Activity的内部类HostCallbacks
mContainer.onFindViewById(f.mContainerId);其实就是Activity.this.findViewById(f.mContainerId),而这个就是我们特别熟悉的方法
f.mContainerId在上面的时候已经分析了,是Activity的R.id.fragment_area
注解3,表明f.mView是怎么来的?跟踪代码你会发现就是通过Fragment.onCreateView产生
注解4,就是将f.mView放到ViewGroup中,这里就是把Activity的View和Fragment的View关联起来

总结

Activity传入给Fragment的是父类,Fragment是将自己的子类全部加载到Activity的父类中

上一篇 下一篇

猜你喜欢

热点阅读