• LinearLayout具体解释三:LayoutInflater创建View过程分析


    上次讲到以下这么一段代码,这段代码的作用就是解析xml文件成为view并显示到屏幕上的。

     @Override
     //设置contentview,也就是activity或fragment载入视图,即view的函数。接受的參数是资源id
        public void setContentView(int layoutResID) {
        //mContentParent是个ViewGroup ,这里mContentParent == null肯定是成立的
            if (mContentParent == null) {
            //成立后就会执行这一句话,从字面意思就能够看出,是安装解析器来着
                installDecor();
            } else {
                mContentParent.removeAllViews();
            }
            //这一句话開始解析并初始化资源了
            mLayoutInflater.inflate(layoutResID, mContentParent);
            //取得对应的回调
            final Callback cb = getCallback();
            if (cb != null) {
            //一旦有回调被调用了,就要通知视图改变
                cb.onContentChanged();
            }
        }


    纵观上面的一段代码,可能最实用的无非这么一句

     mLayoutInflater.inflate(layoutResID, mContentParent);
    
    他解析了id为layoutResId的资源。

    mLayoutInflater这个成员变量,说起这个东西。又是一堆废话要讲。大家千万不要嫌我啰嗦。由于终于我会回到一个很实用的主题。在阐述这个主题之前。这些“小知识”都是必备的,就比方说爱爱之前总要来点前戏对吧偷笑

    假设你听说过Fragment,那么应该知道fragment中载入视图是通过类似

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    			Bundle savedInstanceState) {
    		super.onCreateView(inflater, container, savedInstanceState);
    		View layout = inflater.inflate(R.layout.main_activity_menu, null);
    		initLayouView(layout);
    		return layout;
    	}

    这种代码实现的。

    这就是inflate的作用。他就是用来解析xml并显示到屏幕的,至于解析的代码我这边就不多做阐述了,毕竟已经超越了我们的主题太远。我们还是看inflate是怎样给解析的xml分配内存。并加入到view上的吧!

    这里是LayoutInflater.java的源码

    当中inflate函数的实如今这里:

        public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
            synchronized (mConstructorArgs) {
                final AttributeSet attrs = Xml.asAttributeSet(parser);
                mConstructorArgs[0] = mContext;
                View result = root;
    
                try {
                    int type;
                    while ((type = parser.next()) != XmlPullParser.START_TAG &&
                            type != XmlPullParser.END_DOCUMENT) {
                        // Empty
                    }
    
                    if (type != XmlPullParser.START_TAG) {
                        throw new InflateException(parser.getPositionDescription()
                                + ": No start tag found!");
                    }
    		//这里取得XML标签名字,比方说LinearLayout
                    final String name = parser.getName();
    
                    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, attrs);
                    } else {
                        // 在此处创建视图,參数是前面取得的name,也就是说取得了LinearLayout開始new这个对象了!

    第二个參数就是这个视图的属性 View temp = createViewFromTag(name, attrs); //下面的代码省略......


    以上的代码中。注意这一行:

     View temp = createViewFromTag(name, attrs);

    这一行就是通过解析tag来创建view的,这种方法的实现例如以下:

    //这里的整个过程是:先推断是不是view,假设是的话。再取得属性值
        View createViewFromTag(String name, AttributeSet attrs) {
            if (name.equals("view")) {
                name = attrs.getAttributeValue(null, "class");
            }
    
            try {//这里的mFactory是一个叫做Factory的interface,在Inflater类构造的时候新建了mFactory对象
                View view = (mFactory == null) ? null : mFactory.onCreateView(name,
                        mContext, attrs);
    
                if (view == null) {
                    if (-1 == name.indexOf('.')) {
                        view = onCreateView(name, attrs);
                    } else {
                        view = createView(name, null, attrs);
                    }
                }
    
               //下面代码省略...
    

    再关注里面的

                        view = createView(name, null, attrs);
    

    这句话,正式開始创建了!

    public final View createView(String name, String prefix, AttributeSet attrs)
                throws ClassNotFoundException, InflateException {
            //这里取得了xml的标签,比方说LinearLayout,这个构造器类是通过java的反射获取对象以及參数
            Constructor constructor = sConstructorMap.get(name);
            Class clazz = null;
    
            try {
                if (constructor == null) {
                    // 这个是我们熟悉的类载入器。是另外一种初始化对象的方法(第一种是直接new出来)
                    clazz = mContext.getClassLoader().loadClass(
                            prefix != null ?

    (prefix + name) : name); if (mFilter != null && clazz != null) { boolean allowed = mFilter.onLoadClass(clazz); if (!allowed) { failNotAllowed(name, prefix, attrs); } } constructor = clazz.getConstructor(mConstructorSignature); 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 = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name); boolean allowed = clazz != null && mFilter.onLoadClass(clazz); mFilterMap.put(name, allowed); if (!allowed) { failNotAllowed(name, prefix, attrs); } } else if (allowedState.equals(Boolean.FALSE)) { failNotAllowed(name, prefix, attrs); } } } Object[] args = mConstructorArgs; args[1] = attrs; //上面取得了view,在这里又取得了attrs,换句话说,既取得了对象(比方说LinearLayout),又取得了參数(比方说高度,宽度等等) return (View) constructor.newInstance(args);//下面代码省略...



    创建成功了!


  • 相关阅读:
    AngularJS双向绑定,手动实施观察
    AngularJS的Hello World
    LESS碎语
    chrome浏览器调试报错:Failed to load resource: the server responsed width a status of 404 (Not Found)…http://127.0.0.1:5099/favicon.ico
    AngularJS报错:[$compile:tpload]
    Javascript中的依赖注入
    使用HTML5和CSS3碎语
    在Brackets中使用Emmet
    使用Brackets
    Bootstrap碎语
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6795664.html
Copyright © 2020-2023  润新知