setcontentview流程

藏宝库编辑 2024-10-3 06:16:00 127 0 来自 中国
1.activity的setcontent流程

public void setContentView(@LayoutRes int layoutResID) {        getWindow().setContentView(layoutResID);        initWindowDecorActionBar();    }这内里是phonewindow调用setcontentview
@Override    public void setContentView(int layoutResID) {        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window        // decor, when theme attributes and the like are crystalized. Do not check the feature        // before this happens.        if (mContentParent == null) {            installDecor();//1.创建 DecorView 拿到 mContentParent        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            mContentParent.removeAllViews();        }        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                    getContext());            transitionTo(newScene);        } else {            mLayoutInflater.inflate(layoutResID, mContentParent);2.将本身的xml结构加载进mContentParent内里        }        mContentParent.requestApplyInsets();        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            cb.onContentChanged();        }        mContentParentExplicitlySet = true;    } private void installDecor() {        mForceDecorInstall = false;        if (mDecor == null) {            mDecor = generateDecor(-1);//天生Decorview            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);            mDecor.setIsRootNamespace(true);            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);            }        } else {            mDecor.setWindow(this);        }        if (mContentParent == null) {            mContentParent = generateLayout(mDecor);返回contentParent,一些activity的体系主题在内里设置好比screen_custom_title ,R.layout.screen_simple            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.2.AppCompatActivity的setcontentview流程

getDelegate().setContentView(layoutResID);@Override    public void setContentView(View v) {        ensureSubDecor();        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);        contentParent.removeAllViews();        contentParent.addView(v);        mAppCompatWindowCallback.getWrapped().onContentChanged();    } mSubDecor = createSubDecor();createSubDecor()方法内里重要看 // Now let's make sure that the Window has installed its decor by retrieving it        ensureWindow();//拿到phonewindow        mWindow.getDecorView();//也就是调用installDecorfinal ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);        if (windowContentView != null) {            // There might be Views already added to the Window's content view so we need to            // migrate them to our content view            while (windowContentView.getChildCount() > 0) {                final View child = windowContentView.getChildAt(0);                windowContentView.removeViewAt(0);                contentView.addView(child);            }            // Change our content FrameLayout to use the android.R.id.content id.            // Useful for fragments.            windowContentView.setId(View.NO_ID);//修改contentview的id变成android.R.id.content            contentView.setId(android.R.id.content);            // The decorContent may have a foreground drawable set (windowContentOverlay).            // Remove this as we handle it ourselves            if (windowContentView instanceof FrameLayout) {                ((FrameLayout) windowContentView).setForeground(null);            }        }        // Now set the Window's content view with the decor        mWindow.setContentView(subDecor);总结

1.activity中setcontentview流程

1.installDecor()->mDecor = generateDecor(-1)天生DecorView->mContentParent =generateLayout(mDecor);加载体系结构到Decorview,mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
--> ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);内里的@android:id/content赋值给mContentParent
2.mLayoutInflater.inflate(layoutResID, mContentParent);
2.AppCompatActivity的setcontentview流程

1.AppCompatDelegate.setContentView ->ensureSubDecor()->createSubDecor内里调用ensureWindow(); // 从Activity 那PhoneWindow,mWindow.getDecorView()内里调用installDecor()
-> final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
-> windowContentView.setId(View.NO_ID); // 将原始的 content id 置为 NO_ID
-> contentView.setId(android.R.id.content); // subDecerView R.id.action_bar_activity_content -> 置为 content
-> mWindow.setContentView(subDecor); //
-> ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
接下来分析mLayoutInflater.inflate(layoutResID, mContentParent);

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {        synchronized (mConstructorArgs) {            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");            final Context inflaterContext = mContext;            final AttributeSet attrs = Xml.asAttributeSet(parser);            Context lastContext = (Context) mConstructorArgs[0];            mConstructorArgs[0] = inflaterContext;            View result = root;            try {                advanceToRootNode(parser);                final String name = parser.getName();                if (DEBUG) {                    System.out.println("**************************");                    System.out.println("Creating root view: "                            + name);                    System.out.println("**************************");                }               //假如标签是MERGE到这段代码里                if (TAG_MERGE.equals(name)) {                    if (root == null || !attachToRoot) {                        throw new InflateException("<merge /> can be used only with a valid "                                + "ViewGroup root and attachToRoot=true");                    }                    rInflate(parser, root, inflaterContext, attrs, false);                } else {                    // Temp is the root view that was found in the xml              //重要看这句话                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);                    ViewGroup.LayoutParams params = null;                    if (root != null) {                        if (DEBUG) {                            System.out.println("Creating params from root: " +                                    root);                        }                        // Create layout params that match root, if supplied                        params = root.generateLayoutParams(attrs);                        if (!attachToRoot) {                            // Set the layout params for temp if we are not                            // attaching. (If we are, we use addView, below)                            temp.setLayoutParams(params);                        }                    }                    if (DEBUG) {                        System.out.println("-----> start inflating children");                    }                    // Inflate all children under temp against its context.创建子结构,然后再调用createViewFromTag                    rInflateChildren(parser, temp, attrs, true);                    if (DEBUG) {                        System.out.println("-----> done inflating children");                    }                    // We are supposed to attach all the views we found (int temp)                    // to root. Do that now.                    if (root != null && attachToRoot) {                        root.addView(temp, params);                    }                    // Decide whether to return the root that was passed in or the                    // top view found in xml.                    if (root == null || !attachToRoot) {                        result = temp;                    }                }            } catch (XmlPullParserException e) {                final InflateException ie = new InflateException(e.getMessage(), e);                ie.setStackTrace(EMPTY_STACK_TRACE);                throw ie;            } catch (Exception e) {                final InflateException ie = new InflateException(                        getParserStateDescription(inflaterContext, attrs)                        + ": " + e.getMessage(), e);                ie.setStackTrace(EMPTY_STACK_TRACE);                throw ie;            } finally {                // Don't retain static reference on context.                mConstructorArgs[0] = lastContext;                mConstructorArgs[1] = null;                Trace.traceEnd(Trace.TRACE_TAG_VIEW);            }            return result;        }    }查察重要看 if (view == null) {                final Object lastContext = mConstructorArgs[0];                mConstructorArgs[0] = context;                try {                    if (-1 == name.indexOf('.')) {                        //假如是线性相对等没有.的结构走这个                        view = onCreateView(context, parent, name, attrs);                    } else {                       //好比androidx.constraintlayout.widget.ConstraintLayout                        view = createView(context, name, null, attrs);                    }                } finally {                    mConstructorArgs[0] = lastContext;                }            }点击进去最后都会调用到LayoutInflater的createView方法clazz = Class.forName(prefix != null ? (prefix + name) : name, false,mContext.getClassLoader()).asSubclass(View.class);constructor = clazz.getConstructor(mConstructorSignature);final View view = constructor.newInstance(args);通过反射天生view丢两张结构图

2.png inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) 表明
第一个是加载的资源文件
第二个父控件view
第三个是否attachToRoot内里带有addview功能,就是是否想让其处于某一个容器中
假如父控件设置为null就会使加载的子控件的父控件设置的长宽失效,子控件的巨细由子控件内里的子view决定
ViewStub跟include差不多,懒加载隐蔽结构,他就是一个宽高都为0的view,这里必要注意的一点是,当ViewStub被inflate到parent时,ViewStub就被remove掉了,即当前view hierarchy中不再存在ViewStub,而是利用对应的layout视图代替。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-23 16:09, Processed in 0.194281 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表