美文网首页Android进化
Activity与Fragment怎么关联?

Activity与Fragment怎么关联?

作者: 锄禾豆 | 来源:发表于2019-11-14 15:53 被阅读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的父类中

    相关文章

      网友评论

        本文标题:Activity与Fragment怎么关联?

        本文链接:https://www.haomeiwen.com/subject/uuvrictx.html