AndroidUI--setContentView

这篇具有很好参考价值的文章主要介绍了AndroidUI--setContentView。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

一、继承自Activity

AndroidUI--setContentView,Android,android

1、Activity.setContentView

AndroidUI--setContentView,Android,android
Activity中setContentVIew调用了getWindow().setContentView(view, params);
getWindow返回的是mWindow,mWindow是PhoneWindow对象,在attach中初始化

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

AndroidUI--setContentView,Android,android

2、PhoneWindow.setContentView

该方法主要目的是创建DecorView 拿到Content
AndroidUI--setContentView,Android,android

2.1 installDecor

在installDecor方法中创建DecorView并拿到Content:
AndroidUI--setContentView,Android,android
AndroidUI--setContentView,Android,android
generateDecor创建DecorView
AndroidUI--setContentView,Android,android
generateLayout较长,用于生成和配置窗口(Activity 的视图容器)的布局和样式。
AndroidUI--setContentView,Android,android
AndroidUI--setContentView,Android,android

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

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

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

AndroidUI--setContentView,Android,android
其中ID为content的FrameLayout就是mContentParent

二、继承自AppCompatActivity

AndroidUI--setContentView,Android,android

1、AppCompatActivity.setContentView

AndroidUI--setContentView,Android,android
AndroidUI--setContentView,Android,android

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

AndroidUI--setContentView,Android,android

1.1、ensureSubDecor

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

AndroidUI--setContentView,Android,android

createSubDecor又调用ensureWindow,ensureWindow是对window对象检查,给mWindow变量赋值,之后执行getDecorView
AndroidUI--setContentView,Android,android

此时mWindow是一个PhoneWindow对象,调用PhoneWindow的getDecorView
AndroidUI--setContentView,Android,android
getDecorView中又调用了installDecor,这个方法在继承Activity中出现过,此后流程不再赘述

AndroidUI--setContentView,Android,android
AndroidUI--setContentView,Android,android
crateDecor之后还会去获取subDecor,看最简单的abc_screen_simple
AndroidUI--setContentView,Android,android
abc_screen_content_include.xml
AndroidUI--setContentView,Android,android
此时subDecor有布局了
之后会通过findViewById去获取上面的ContentFrameLayout
AndroidUI--setContentView,Android,android

之后执行final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
AndroidUI--setContentView,Android,android
该处获取的是Activity的,也就是R.layout.screen_simple的content
AndroidUI--setContentView,Android,android
之后将这个原始的content id置为NO_ID 将subDecerView的id置为content 进行一个替换

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

不管是继承自Activity还是AppCompatActivity的setContentVIew,之后都会调用这么一句代码,该代码就是创建R.layout.main_activity的View
AndroidUI--setContentView,Android,android
调用res.getLayout进行xml解析
调用inflate进行渲染

    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

AndroidUI--setContentView,Android,android
红框中会判断name中是否有点,有执行onCreateView没有执行createView
有点一般的就是一些第三方组件或者自定义组件,比如androidx.constraintlayout.widget.ConstraintLayout

Layoutinflater是一个抽象类,onCreateView的具体实现在其实现类PhoneLayoutInflater
在onCreateView中,最终还是调用了createView
AndroidUI--setContentView,Android,android

AndroidUI--setContentView,Android,android
此处的prefix是一些前缀,用于在调用createView时进行补全
最后返回了super.onCreateView,父类的onCreateView中补全了android.view
AndroidUI--setContentView,Android,android
然后看createView

    @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

AndroidUI--setContentView,Android,android
rInflateChildren调用的是rinflate文章来源地址https://www.toymoban.com/news/detail-839529.html

    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();
        }
    }

到了这里,关于AndroidUI--setContentView的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AndroidUI--SlidingMenu使用例子,在线面试指南

    } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } private Fragment mContent; /** 切换视图 @param fragment */ public void switchContent(Fragment fragment) { mContent = fragment; getSupportFragmentManager().beginTr

    2024年03月25日
    浏览(39)
  • 反射工具类,如斯优雅,androidui基础教程

    根据如上注释相信大家也可以理解一二了,如果还想了解更多使用方式,可以查看我写的单元测试类 ReflectUtilsTest,其使用方式就介绍到这里,下面介绍其实现方式。 实现的话是站在 jOOR 的肩膀上进行改造,其内部封装了一个 private final Object object; 变量,每次进行反射操作时

    2024年04月24日
    浏览(25)
  • androidui图形化,,理论+实战双管齐下

    1、拓宽知识面 兴趣来了挡也挡不住!从最初开始学习编程,从ASP到ASP.net,JS,Winform,Java,C++,PHP,Python,都是自学! 不过这里要说一下,如果没有一两门编程语言比较熟悉的情况下,最好还是不要自学;入门是最难的,最浪费时间的!如果有个人带着你学习的话,那甚至能节省你

    2024年04月26日
    浏览(22)
  • 【AndroidUI设计】主界面设计-Toolbar的简单使用

    描述:需要设计一个主界面,菜单通过主界面的左边界划入,实现点击跳转修改主界面内容的一个效果,并且点击非内容区域恢复原界面的一个效果。做到菜单的弹出,其实还可以加难度,通过向右滑动实现菜单的弹出。这里就作为一个思考问题,其实在我之前的几篇博客里

    2024年02月10日
    浏览(46)
  • androidui开发框架,,三级缓存框架问题你都了解了吗

    第一部分是我前端面试的经验总结,第二部分是我认为比较有思考空间的题目 一份漂亮的简历,需要包括以下部分(排版由上而下) 个人亮点(专精领域,个人博客,开源项目) 教育经历(毕业院校,在校经历、荣誉) 工作经历(实习) 项目经历 专业技能 扎实的前端基础

    2024年03月26日
    浏览(39)
  • Android studio导入Android源码(AOSP Android 14)

    1. 完整编译AOSP源码 有些java文件是在编译过程中动态生成的,需要完整编译一遍,源码的依赖才能完整。 2. 生成IDE导入的工程文件 执行完成后,在AOSP根目录下生成文件: 3. 导入前,编辑工程文件 (这步很重要,影响代码的加载速度和跳转) 编辑android.iml文件,需要修改2部

    2024年02月10日
    浏览(39)
  • Android入门教程||Android 架构||Android 应用程序组件

    Android 操作系统是一个软件组件的栈,在架构图中它大致可以分为五个部分和四个主要层。 在所有层的最底下是 Linux - 包括大约115个补丁的 Linux 3.6。它提供了基本的系统功能,比如进程管理,内存管理,设备管理(如摄像头,键盘,显示器)。同时,内核处理所有 Linux 所擅

    2024年02月13日
    浏览(42)
  • Android 面试(Android 篇)

    原理: 触发条件: 引起条件: 查看方式 避免建议: 原因 解决 扩展 内存抖动 内存溢出 扩展: 内存泄漏 问:常见的内存泄露有哪些?如何解决? 问:为什么单例模式会持有当前activity的引用,无法释放 备注: standard:标准模式, 2 从 A 跳转 B 3 从 B 跳转 A singleTop 栈顶复用模

    2024年02月04日
    浏览(34)
  • 【Android】Android虚拟机

    Android的虚拟机主要有两种: Dalvik 虚拟机 和 ART(Android Runtime)虚拟机 。 Dalvik 虚拟机 Dalvik 虚拟机是 Android 早期使用的虚拟机,它 基于寄存器架构 。从Android 2.2版本开始,支持 JIT即时编译(Just In Time) 在程序运行的过程中进行选择热点代码(经常执行的代码)进行编译或者

    2024年02月07日
    浏览(39)
  • Android版本API对应表(Android9.0-Android 14.0)

    Android 14(API 级别 34) Android 13(API 级别 33) Android 12(API 级别 31、32) Android 11(API 级别 30) Android 10(API 级别 29) Android 9(API 级别 28) 参考文档

    2024年02月02日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包