Fragment的onCreateView创建的view是如何加入到Activity的
发布日期:2021-11-21 16:14:11 浏览次数:30 分类:技术文章

本文共 14539 字,大约阅读时间需要 48 分钟。

**

Fragment的onCreateView创建的view是如果加入到Activity的过程分析

**

1.简单介绍一下fragment的使用
在activity的布局里添加一个ViewGroup并设置一个id,使用的时候通过这个id添加一个fragment。这个过程相信大家都非常的清楚所以很简单的说明一下。

2.开始正式说明这个添加过程

1,在FragmentActivity里有一个变量mFragments

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

这个mFragments 是用来管理控制fragment的,请看他的创建方法,new了一个HostCallbacks对象,这个对象是activity与fragmeController交互的回调

class HostCallbacks extends FragmentHostCallback
{ public HostCallbacks() { super(FragmentActivity.this /*fragmentActivity*/); } @Override public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { FragmentActivity.this.dump(prefix, fd, writer, args); } @Override public boolean onShouldSaveFragmentState(Fragment fragment) { return !isFinishing(); } @Override public LayoutInflater onGetLayoutInflater() { return FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.this); } @Override public FragmentActivity onGetHost() { return FragmentActivity.this; } @Override public void onSupportInvalidateOptionsMenu() { FragmentActivity.this.supportInvalidateOptionsMenu(); } @Override public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) { FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode); } @Override public void onStartActivityFromFragment( Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) { FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode, options); } @Override public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) throws IntentSender.SendIntentException { FragmentActivity.this.startIntentSenderFromFragment(fragment, intent, requestCode, fillInIntent, flagsMask, flagsValues, extraFlags, options); } @Override public void onRequestPermissionsFromFragment(@NonNull Fragment fragment, @NonNull String[] permissions, int requestCode) { FragmentActivity.this.requestPermissionsFromFragment(fragment, permissions, requestCode); } @Override public boolean onShouldShowRequestPermissionRationale(@NonNull String permission) { return ActivityCompat.shouldShowRequestPermissionRationale( FragmentActivity.this, permission); } @Override public boolean onHasWindowAnimations() { return getWindow() != null; } @Override public int onGetWindowAnimations() { final Window w = getWindow(); return (w == null) ? 0 : w.getAttributes().windowAnimations; } @Override public void onAttachFragment(Fragment fragment) { FragmentActivity.this.onAttachFragment(fragment); } @Nullable @Override public View onFindViewById(int id) { return FragmentActivity.this.findViewById(id); } @Override public boolean onHasView() { final Window w = getWindow(); return (w != null && w.peekDecorView() != null); } }

在这个回调的方法都很重要,其中

@Override        public FragmentActivity onGetHost() {            return FragmentActivity.this;        }                @Nullable        @Override        public View onFindViewById(int id) {            return FragmentActivity.this.findViewById(id);        }

这两个方法是把fragment的view添加到activity最重要的2个方法,onFindViewById(int id)的这个id 就是

我们activity布局时给fragment设置ViewGroup ID。
FragmentController 里的private final FragmentHostCallback<?> mHost;就是通过onGetHost方法赋值。

FragmentHostCallback里面的几个重要变量

private final Activity mActivity;    final Context mContext;    private final Handler mHandler;    final int mWindowAnimations;    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

这几个变量看名字也能猜出他们是干什么的,其中mFragmentManager 是主要负责管理fragment的各种操作,包括onCreateView这个方法

现在我们再看看FragmentManagerImpl这个类里的2个重要变量

FragmentHostCallback mHost;    FragmentContainer mContainer;

mHost就是HostCallbacks 的实例对象

mContainer看名字是一个Fragment的容器,他的代码如下:

public abstract class FragmentContainer {    /**     * Return the view with the given resource ID. May return {@code null} if the     * view is not a child of this container.     */    @Nullable    public abstract View onFindViewById(@IdRes int id);    /**     * Return {@code true} if the container holds any view.     */    public abstract boolean onHasView();    /**     * Creates an instance of the specified fragment, can be overridden to construct fragments     * with dependencies, or change the fragment being constructed. By default just calls     * {@link Fragment#instantiate(Context, String, Bundle)}.     */    public Fragment instantiate(Context context, String className, Bundle arguments) {        return Fragment.instantiate(context, className, arguments);    }}

instantiate用来创建fragment的实例,onFindViewById最后会通过

@Nullable        @Override        public View onFindViewById(int id) {            return FragmentActivity.this.findViewById(id);        }

这个方法来获取我们给fragment准备的ViewGroup并添加fragment onCreateView返回的view,这样fragment的view就添加到acti里了

那有人可能就要问了mContainer是在哪初始化的,在FragmentManagerImpl的如下方法里

public void attachController(FragmentHostCallback host,            FragmentContainer container, Fragment parent) {        if (mHost != null) throw new IllegalStateException("Already attached");        mHost = host;        mContainer = container;        mParent = parent;    }

再看看attachController是在哪调用的呢?这时又回到了FragmentController里

public void attachHost(Fragment parent) {        mHost.mFragmentManager.attachController(                mHost, mHost /*container*/, parent);    }

mHost 是不是很熟悉,前面介绍过了

3.最后看看mContainer是怎么添加view的

在FragmentManagerImpl的onCreateView方法里,方法比较长这里完整贴出方便看清楚过程

(说明一下这原码是在android.support.v4.app包下找的,不同版本内容可能略有不同)
在这里插入图片描述

@Override    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {        if (!"fragment".equals(name)) {            return null;        }        String fname = attrs.getAttributeValue(null, "class");        TypedArray a =  context.obtainStyledAttributes(attrs, FragmentTag.Fragment);        if (fname == null) {            fname = a.getString(FragmentTag.Fragment_name);        }        int id = a.getResourceId(FragmentTag.Fragment_id, View.NO_ID);        String tag = a.getString(FragmentTag.Fragment_tag);        a.recycle();        if (!Fragment.isSupportFragmentClass(mHost.getContext(), fname)) {            // Invalid support lib fragment; let the device's framework handle it.            // This will allow android.app.Fragments to do the right thing.            return null;        }        int containerId = parent != null ? parent.getId() : 0;        if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {            throw new IllegalArgumentException(attrs.getPositionDescription()                    + ": Must specify unique android:id, android:tag, or have a parent with an id for " + fname);        }        // If we restored from a previous state, we may already have        // instantiated this fragment from the state and should use        // that instance instead of making a new one.        Fragment fragment = id != View.NO_ID ? findFragmentById(id) : null;        if (fragment == null && tag != null) {            fragment = findFragmentByTag(tag);        }        if (fragment == null && containerId != View.NO_ID) {            fragment = findFragmentById(containerId);        }        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x"                + Integer.toHexString(id) + " fname=" + fname                + " existing=" + fragment);        if (fragment == null) {            fragment = mContainer.instantiate(context, fname, null);            fragment.mFromLayout = true;            fragment.mFragmentId = id != 0 ? id : containerId;            fragment.mContainerId = containerId;            fragment.mTag = tag;            fragment.mInLayout = true;            fragment.mFragmentManager = this;            fragment.mHost = mHost;            fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);            addFragment(fragment, true);        } else if (fragment.mInLayout) {            // A fragment already exists and it is not one we restored from            // previous state.            throw new IllegalArgumentException(attrs.getPositionDescription()                    + ": Duplicate id 0x" + Integer.toHexString(id)                    + ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId)                    + " with another fragment for " + fname);        } else {            // This fragment was retained from a previous instance; get it            // going now.            fragment.mInLayout = true;            fragment.mHost = mHost;            // If this fragment is newly instantiated (either right now, or            // from last saved state), then give it the attributes to            // initialize itself.            if (!fragment.mRetaining) {                fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);            }        }        // If we haven't finished entering the CREATED state ourselves yet,        // push the inflated child fragment along. This will ensureInflatedFragmentView        // at the right phase of the lifecycle so that we will have mView populated        // for compliant fragments below.        if (mCurState < Fragment.CREATED && fragment.mFromLayout) {            moveToState(fragment, Fragment.CREATED, 0, 0, false);        } else {            moveToState(fragment);        }        if (fragment.mView == null) {            throw new IllegalStateException("Fragment " + fname                    + " did not create a view.");        }        if (id != 0) {            fragment.mView.setId(id);        }        if (fragment.mView.getTag() == null) {            fragment.mView.setTag(tag);        }        return fragment.mView;    }

在这个很长的方法里通过fragment = mContainer.instantiate(context, fname, null);创建fragment,

通过 moveToState(fragment);来添加view。这个方法也很长里面通过不同状态进行不同的操作
这里只贴出create的部分

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;                            if (f.mContainerId != 0) {                                if (f.mContainerId == View.NO_ID) {                                    throwException(new IllegalArgumentException(                                            "Cannot create fragment "                                                    + f                                                    + " for a container view with no id"));                                }                                //通过id获取activity的ViewGroup                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);                                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;                            //调用fragment的onCreateView返回的view赋值                            f.mView = f.performCreateView(f.performGetLayoutInflater(                                    f.mSavedFragmentState), container, f.mSavedFragmentState);                            if (f.mView != null) {                                f.mInnerView = f.mView;                                f.mView.setSaveFromParentEnabled(false);                                if (container != null) {                                	//把fragment创建的view添加到了activity的设置的ViewGroup里                                    container.addView(f.mView);                                }                                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;                            } else {                                f.mInnerView = null;                            }                        }                        f.performActivityCreated(f.mSavedFragmentState);                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);                        if (f.mView != null) {                            f.restoreViewState(f.mSavedFragmentState);                        }                        f.mSavedFragmentState = null;                    }

关键部分加入了注释,到这里整个过程就都说了,希望对大家有用,哪里时候的不对的请指出,谢谢

转载地址:https://blog.csdn.net/yx19861211/article/details/93858814 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android RecyclerView Glide 滑动时图片加载的优化
下一篇:Android7.0、8.0应用内安装apk的问题

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2023年09月19日 05时45分37秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

日本数字货币可能在2月交出答卷,中国和Libra或是主要驱动力 2019-03-07
投资加密货币的三大策略:天时、地利与人和 2019-03-07
2020 区块链进入关键时期!比特币区块链或将分道扬镳、Libra 苦难继续... 2019-03-07
BTC价格回暖,矿机断货,矿场却没人了…… 2019-03-07
ChainNode测评:WOOKONG Bio&Solo硬件钱包 全体验 2019-03-07
捐款去向存疑,慈善基金区块链化迫在眉睫 2019-03-07
福布斯公布“金融科技50强”,6家区块链公司上榜 2019-03-07
比特币加速闯入DeFi世界,揭密火币上线的HBTC 2019-03-07
网友爆料:Reddit疑似开发区块链打赏功能 2019-03-07
资金情绪指标:一个量化择时的新参考 | QKL123研报 2019-03-07
DeFi 1日连遭2次攻击,dForce疑被盗2500万美元资产 2019-03-07
“拉飞”的Hive vs 尴尬的Steem:谁是最大的赢家? 2019-03-07
如何寻找区块链应用场景?这三个方法请收好 2019-03-07
《链上带货女王》第二期5月来袭,直播间商品价格减半,甚至更低! 2019-03-07
ETH大涨背后:Grayscale大举买入2020年近一半已开采的ETH,以太坊2.0让投资者兴趣高涨... 2019-03-07
太难了!禁令解除后依然无法获取银行服务,印度交易所向央行寻求帮助 2019-03-07
李礼辉最新分享:未来的全球数字经济竞争中,数字货币将居于核心地位 2019-03-07
2020年值得体验的8款DeFi钱包 2019-03-07
DeFi“假币”泛滥,去中心化交易所上币政策太开放了? 2019-03-07
A股牛 vs DeFi牛,选谁不会被套? 2019-03-07