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进行渲染

java 复制代码
    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.
                    //解析并创建子视图,该方法是一个递归方法
                    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;
        }
    }

1、createViewFromTag

红框中会判断name中是否有点,有执行onCreateView没有执行createView

有点一般的就是一些第三方组件或者自定义组件,比如androidx.constraintlayout.widget.ConstraintLayout

Layoutinflater是一个抽象类,onCreateView的具体实现在其实现类PhoneLayoutInflater

在onCreateView中,最终还是调用了createView

此处的prefix是一些前缀,用于在调用createView时进行补全

最后返回了super.onCreateView,父类的onCreateView中补全了android.view

然后看createView

java 复制代码
    @Nullable
    public final View createView(@NonNull Context viewContext, @NonNull String name,
            @Nullable String prefix, @Nullable AttributeSet attrs)
            throws ClassNotFoundException, InflateException {
        Objects.requireNonNull(viewContext);
        Objects.requireNonNull(name);
        Constructor<? extends View> constructor = sConstructorMap.get(name);
        if (constructor != null && !verifyClassLoader(constructor)) {
            constructor = null;
            sConstructorMap.remove(name);
        }
        Class<? extends View> 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 constructor
                if (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);
                        }
                    } else if (allowedState.equals(Boolean.FALSE)) {
                        failNotAllowed(name, prefix, viewContext, attrs);
                    }
                }
            }

            Object lastContext = mConstructorArgs[0];
            mConstructorArgs[0] = viewContext;
            Object[] args = mConstructorArgs;
            args[1] = attrs;

            try {
            		//执行构造,创建View对象
                final View view = constructor.newInstance(args);
                if (view instanceof ViewStub) {
                    // Use the same context when inflating ViewStub later.
                    final ViewStub viewStub = (ViewStub) view;
                    viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
                }
                return view;
            } finally {
                mConstructorArgs[0] = lastContext;
            }
        } catch (NoSuchMethodException e) {
            final InflateException ie = new InflateException(
                    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 subclass
            final InflateException ie = new InflateException(
                    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) {
            final InflateException ie = new InflateException(
                    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

java 复制代码
    void rInflate(XmlPullParser parser, View parent, Context context,
            AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {

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

        if (pendingRequestFocus) {
            parent.restoreDefaultFocus();
        }

        if (finishInflate) {
            parent.onFinishInflate();
        }
    }
相关推荐
似霰29 分钟前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶29 分钟前
Android——网络请求
android
干一行,爱一行31 分钟前
android camera data -> surface 显示
android
断墨先生1 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员2 小时前
PHP常量
android·ide·android studio
萌面小侠Plus3 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机
慢慢成长的码农3 小时前
Android Profiler 内存分析
android
大风起兮云飞扬丶3 小时前
Android——多线程、线程通信、handler机制
android
L72564 小时前
Android的Handler
android
清风徐来辽4 小时前
Android HandlerThread 基础
android