0


AndroidUI--setContentView

我们的Activity通常继承自Activity或者AppCompatActivity,这两个setContentView流程是不同的

一、继承自Activity

在这里插入图片描述

1、Activity.setContentView

在这里插入图片描述
Activity中setContentVIew调用了getWindow().setContentView(view, params);
getWindow返回的是mWindow,mWindow是PhoneWindow对象,在attach中初始化

当创建Activity、Dialog、PopupWindow、Toast时都会创建PhoneWindow对象

在这里插入图片描述

2、PhoneWindow.setContentView

该方法主要目的是创建DecorView 拿到Content
在这里插入图片描述

2.1 installDecor

在installDecor方法中创建DecorView并拿到Content:
在这里插入图片描述
在这里插入图片描述
generateDecor创建DecorView
在这里插入图片描述
generateLayout较长,用于生成和配置窗口(Activity 的视图容器)的布局和样式。
在这里插入图片描述
在这里插入图片描述

上图红框为两行较为重要的代码
onResourcesLoaded是将上面的R.layout.simple等这种layout添加到DecorView中
第二个红框是拿到ViewGroup对象,最后返回的就是这个对象

在这之上,该方法会加载一些layout,以最简单的screen_simple举例

注意:DecorView其实就是个FrameLayout,是整个窗口的根视图,它包括应用程序内容的视图以及窗口可能有的系统级视图,如状态栏和导航栏。

在这里插入图片描述
其中ID为content的FrameLayout就是mContentParent

二、继承自AppCompatActivity

在这里插入图片描述

1、AppCompatActivity.setContentView

在这里插入图片描述
在这里插入图片描述

与继承自Activity的不同,这里是调用的AppCompatDelegate的setContentView
AppCompatDelegate是一个接口,具体实现在AppCompatDelegateImpl:

在这里插入图片描述

1.1、ensureSubDecor

调用ensureSubDecor,下面的与继承Activity的类似
ensureSubDecor又调用createSubDecor

在这里插入图片描述

createSubDecor又调用ensureWindow,ensureWindow是对window对象检查,给mWindow变量赋值,之后执行getDecorView
在这里插入图片描述

此时mWindow是一个PhoneWindow对象,调用PhoneWindow的getDecorView
在这里插入图片描述
getDecorView中又调用了installDecor,这个方法在继承Activity中出现过,此后流程不再赘述

在这里插入图片描述
在这里插入图片描述
crateDecor之后还会去获取subDecor,看最简单的abc_screen_simple
在这里插入图片描述
abc_screen_content_include.xml
在这里插入图片描述
此时subDecor有布局了
之后会通过findViewById去获取上面的ContentFrameLayout
在这里插入图片描述

之后执行final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
在这里插入图片描述
该处获取的是Activity的,也就是R.layout.screen_simple的content
在这里插入图片描述
之后将这个原始的content id置为NO_ID 将subDecerView的id置为content 进行一个替换

三、LayoutInflater.from(mContext).inflate(resId, contentParent);

不管是继承自Activity还是AppCompatActivity的setContentVIew,之后都会调用这么一句代码,该代码就是创建R.layout.main_activity的View
在这里插入图片描述
调用res.getLayout进行xml解析
调用inflate进行渲染

publicViewinflate(XmlPullParser parser,@NullableViewGroup root,boolean attachToRoot){synchronized(mConstructorArgs){Trace.traceBegin(Trace.TRACE_TAG_VIEW,"inflate");finalContext inflaterContext = mContext;finalAttributeSet attrs =Xml.asAttributeSet(parser);Context lastContext =(Context) mConstructorArgs[0];
            mConstructorArgs[0]= inflaterContext;View result = root;try{advanceToRootNode(parser);//寻找根节点finalString 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){thrownewInflateException("<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//创建根视图finalView 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.//解析并创建子视图,该方法是一个递归方法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){finalInflateException ie =newInflateException(e.getMessage(), e);
                ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;}catch(Exception e){finalInflateException ie =newInflateException(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;}}

1、createViewFromTag

在这里插入图片描述
红框中会判断name中是否有点,有执行onCreateView没有执行createView
有点一般的就是一些第三方组件或者自定义组件,比如androidx.constraintlayout.widget.ConstraintLayout

Layoutinflater是一个抽象类,onCreateView的具体实现在其实现类PhoneLayoutInflater
在onCreateView中,最终还是调用了createView
在这里插入图片描述

在这里插入图片描述
此处的prefix是一些前缀,用于在调用createView时进行补全
最后返回了super.onCreateView,父类的onCreateView中补全了android.view
在这里插入图片描述
然后看createView

@NullablepublicfinalViewcreateView(@NonNullContext viewContext,@NonNullString name,@NullableString prefix,@NullableAttributeSet attrs)throwsClassNotFoundException,InflateException{Objects.requireNonNull(viewContext);Objects.requireNonNull(name);Constructor<?extendsView> constructor = sConstructorMap.get(name);if(constructor !=null&&!verifyClassLoader(constructor)){
            constructor =null;
            sConstructorMap.remove(name);}Class<?extendsView> clazz =null;try{Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);if(constructor ==null){// Class not found in the cache, see if it's real, and try to add it//由于前面补全了前缀,所以这个可以通过包名进行反射,然后创建View对象
                clazz =Class.forName(prefix !=null?(prefix + name): name,false,
                        mContext.getClassLoader()).asSubclass(View.class);if(mFilter !=null&& clazz !=null){boolean allowed = mFilter.onLoadClass(clazz);if(!allowed){failNotAllowed(name, prefix, viewContext, attrs);}}//获取构造对象
                constructor = clazz.getConstructor(mConstructorSignature);
                constructor.setAccessible(true);
                sConstructorMap.put(name, constructor);}else{// If we have a filter, apply it to cached constructorif(mFilter !=null){// Have we seen this name before?Boolean allowedState = mFilterMap.get(name);if(allowedState ==null){// New class -- remember whether it is allowed
                        clazz =Class.forName(prefix !=null?(prefix + name): name,false,
                                mContext.getClassLoader()).asSubclass(View.class);boolean allowed = clazz !=null&& mFilter.onLoadClass(clazz);
                        mFilterMap.put(name, allowed);if(!allowed){failNotAllowed(name, prefix, viewContext, attrs);}}elseif(allowedState.equals(Boolean.FALSE)){failNotAllowed(name, prefix, viewContext, attrs);}}}Object lastContext = mConstructorArgs[0];
            mConstructorArgs[0]= viewContext;Object[] args = mConstructorArgs;
            args[1]= attrs;try{//执行构造,创建View对象finalView view = constructor.newInstance(args);if(view instanceofViewStub){// Use the same context when inflating ViewStub later.finalViewStub viewStub =(ViewStub) view;
                    viewStub.setLayoutInflater(cloneInContext((Context) args[0]));}return view;}finally{
                mConstructorArgs[0]= lastContext;}}catch(NoSuchMethodException e){finalInflateException ie =newInflateException(getParserStateDescription(viewContext, attrs)+": Error inflating class "+(prefix !=null?(prefix + name): name), e);
            ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;}catch(ClassCastException e){// If loaded class is not a View subclassfinalInflateException ie =newInflateException(getParserStateDescription(viewContext, attrs)+": Class is not a View "+(prefix !=null?(prefix + name): name), e);
            ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;}catch(ClassNotFoundException e){// If loadClass fails, we should propagate the exception.throw e;}catch(Exception e){finalInflateException ie =newInflateException(getParserStateDescription(viewContext, attrs)+": Error inflating class "+(clazz ==null?"<unknown>": clazz.getName()), e);
            ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;}finally{Trace.traceEnd(Trace.TRACE_TAG_VIEW);}}

到这里rootView创建好了,之后要创建子View

2、rInflateChildren

在这里插入图片描述
rInflateChildren调用的是rinflate

voidrInflate(XmlPullParser parser,View parent,Context context,AttributeSet attrs,boolean finishInflate)throwsXmlPullParserException,IOException{finalint depth = parser.getDepth();int type;boolean pendingRequestFocus =false;//循环解析XMLwhile(((type = parser.next())!=XmlPullParser.END_TAG||
                parser.getDepth()> depth)&& type !=XmlPullParser.END_DOCUMENT){//跳过非开始标签if(type !=XmlPullParser.START_TAG){continue;}//获取标签名称finalString name = parser.getName();//处理<requestFocus>标签if(TAG_REQUEST_FOCUS.equals(name)){
                pendingRequestFocus =true;consumeChildElements(parser);}elseif(TAG_TAG.equals(name)){//处理<tag>标签parseViewTag(parser, parent, attrs);}elseif(TAG_INCLUDE.equals(name)){//处理<include>标签if(parser.getDepth()==0){thrownewInflateException("<include /> cannot be the root element");}parseInclude(parser, context, parent, attrs);}elseif(TAG_MERGE.equals(name)){//处理<merge>标签thrownewInflateException("<merge /> must be the root element");}else{//对于其他标签,使用createViewFromTag创建视图,生成布局参数,递归调用rInflateChildrenfinalView view =createViewFromTag(parent, name, context, attrs);finalViewGroup viewGroup =(ViewGroup) parent;finalViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);rInflateChildren(parser, view, attrs,true);
                viewGroup.addView(view, params);}}if(pendingRequestFocus){
            parent.restoreDefaultFocus();}if(finishInflate){
            parent.onFinishInflate();}}
标签: android

本文转载自: https://blog.csdn.net/qq_56892136/article/details/136376273
版权归原作者 子夜听雨 所有, 如有侵权,请联系我们删除。

“AndroidUI--setContentView”的评论:

还没有评论