你知道AttributeSet与XmlPullParser的关系吗?

前言

AttributeSet与XmlPullParser这2个接口在解析xml文件时经常配合使用,二者可进行相互转换,理清二者的关系对于深入理解LayoutIflater.inflate()源码时,有着重要作用。
故本文的目的在于理清二者之间的关系,简述XmlPullParser的基本用法,为后续理解LayoutIflater.inflate方法源码打下基础。

类图结构

AttributeSet与XmlPullParser的类图关系如下图所示:


类图结构

AttributeSet接口抽象了访问xml节点属性的方法,XmlPullPaser接口抽象了解析xml文件的方法,这个2个接口具有部分相同的方法声明,如下图所示。这些方法是XmlPull解析常用来访问xml节点属性的方法。

    int getAttributeCount();
    String getAttributeName(int index);
    String getAttributeValue(int index);
    String getAttributeValue(String namespace, String name);
    String getPositionDescription();

AttributeSet与XmlPullParser的关系

在Android中AttributeSet接口的实现类有XmlPullAttribute和Parser(XmlResourceParser接口的实现类,该接口继承了XmlPullParser和AttributeSet接口)。
我们先来看看XmlPullAttribute的实现,部分代码如下:

class XmlPullAttributes implements AttributeSet {
    public XmlPullAttributes(XmlPullParser parser) {
        mParser = parser;
    }

    public int getAttributeCount() {
        return mParser.getAttributeCount();
    }

    public String getAttributeName(int index) {
        return mParser.getAttributeName(index);
    }

    public String getAttributeValue(int index) {
        return mParser.getAttributeValue(index);
    }

    public String getAttributeValue(String namespace, String name) {
        return mParser.getAttributeValue(namespace, name);
    }

    public String getPositionDescription() {
        return mParser.getPositionDescription();
    }

    public int getAttributeNameResource(int index) {
        return 0;
    }

    public int getAttributeListValue(String namespace, String attribute,
            String[] options, int defaultValue) {
        return XmlUtils.convertValueToList(
            getAttributeValue(namespace, attribute), options, defaultValue);
    }
     ............
    //AttributeSet接口的剩余方法实现省略,其实现与getAttributeListValue()方法
    //相似,都依赖XmlUtils与getAttributeValue()。
}

可见该类关联了一个XmlPullParser类型的成员变量(实际上是KXmlParser),AttributeSet接口与XmlPullParser接口相同声明函数的实现都是调用的mParser的同名函数;而AttributeSet接口的其他方法皆依赖于getAttributeValue方法来实现,即也依赖于mParser。
从代码实现来看,很自然的会联想到装饰者设计模式,虽然从类图结构上来看,并非属于严格意义上的装饰者模式,但我想可以将AttributeSet理解为XmlPullParser的装饰者,只不过这个装饰者没有全部装饰而已,只是装饰了XmlParser用于访问xml节点属性的那一部分。
自创部分装饰设计,强行解说2333....
综上所述:AttributeSet是对XmlPullParser的部分装饰,装饰了用于访问xml节点属性的部分。或者理解为AttributeSet是对XmlPullParser中用于访问xml节点属性方法的封装。

至于为什么要这么做呢?拙见如下:

  1. AttributeSet这个接口更适合Android的设计,其语意性更强;如果将View的构造函数中的AttributeSet换为XmlPullParser,看起来是不是有一种别扭的感觉的,而AttributeSet(属性集合)这个命名更易让人理解接受,装饰的作用之一就是可以“改头换面”嘛。
  2. 单一职责原则,XmlPullParser接口的职责不单单是用于访问xml节点的属性,从中分离出一个用于访问节点属性的接口岂不美哉?
  3. 对XmlPullParser中的Xml节点属性访问方法进行扩展,方便使用,如getAttributeIntValue方法可直接获取int类型的属性值,若使用XmlPullParser则只能获取String类型的数据,还需要我们自己转换一次。

下面来看看XmlResourceParser接口。
该接口同时继承了XmlPullParser接口以及AttributeSet接口,作用有二。

  1. 对XmlPullParser起到部分装饰的作用,实现XmlResourceParser接口,即可达到目的。
  2. 继承XmlPullParser接口,实现一个专用于Android Xml资源文件的解析器,如解析layout、drawable等目录下的xml文件。
    Android中的常见打开方式如下:
        Resources resources = getResources();
        XmlResourceParser  parser0 = resources.getXml(R.xml.test);
        XmlResourceParser  parser1 = resources.getLayout(R.layout.activity_main);
        XmlResourceParser  parser2 = resources.getAnimation(R.anim.test);

Drawable目录下的xml解析并未提供我们可直接获取XmlResourceParser的API,其解析封装在ResourseImpl类(@hide)的方法中。

    /**
        * Loads a drawable from XML or resources stream.
        */
    private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,Resources.Theme theme) {
        ............
        if (file.endsWith(".xml")) {
                final XmlResourceParser rp = loadXmlResourceParser(
                        file, id, value.assetCookie, "drawable");
                dr = Drawable.createFromXml(wrapper, rp, theme);
                rp.close();
            } else {
                final InputStream is = mAssets.openNonAsset(
                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
                is.close();
            }
       ............
}

XmlResourceParser的实现类为Parser类,该类属于BlockXml类的一个内部类,用于解析Android中的layout布局文件。
这里说一个小技巧,方便想要自行查看源码的朋友:
在Android Studio中可通过双击Shift键来快速查找类文件,可以查到一些隐藏类文件的源码。
总结
1、AttributeSet接口是对XmlPullParser接口的部分装饰,装饰了XmlPullParser中xml节点属性的访问方法。AttributeSet接口语意性更强,更适合Android架构的整体设计。
2、其实现类无论是Parser还是XmlPullAttribute,它只是起到一个装饰作用,最终对xml节点属性的访问都是通过里面的XmlPullParser的节点属性访问方法来完成的。

至此,AttributeSet与XmlPullParser的关系已经分析清楚,后文只是方便自己后续查看,主要记录XmlPullParser的基本使用。

转换分析

XmlPullParser转换为AttributeSet的方法为:

  Xml.asAttributeSet(parser0);

进去看看源码:

//如果传入的XmlPullParser类型为XmlResourceParser(Parser),返回的就是XmlResourceParser(Parser)
//反之则new 一个XmlPullAttributeSet
 public static AttributeSet asAttributeSet(XmlPullParser parser) {
        return (parser instanceof AttributeSet)
                ? (AttributeSet) parser
                : new XmlPullAttributes(parser);
    }

XmlPullParser的基本使用

由上文可知,Android中XmlPull解析器有2种类型,一种是专用于Android xml资源文件的解析器,一种是org.xmlpull.v1自带的xml解析器,无论是那种类型,对外而言,其用法都一样,这就是面向接口编程的一个好处。
实际应用当中,使用较多的应该是org.xmlpull.v1自带的xml解析器,毕竟Android的专用资源解析器,它已经封装好自动解析了。

         public static void main (String args[])
                throws XmlPullParserException, IOException
        {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            //区分namespace
            factory.setNamespaceAware(true);
            XmlPullParser xpp = factory.newPullParser();
   
           /**
             * 解析最开始并非位于START_DOCUMENT,多次调用next,会依次位于
             * START_DOCUMENT
             * START_TAG(XML节点属性解析只能在该事件类型中进行解析)
             * TEXT(无Text部分“Hello World”则跳过该事件类型)
             * END_TAG
             * End document
             */
            xpp.setInput( new StringReader ( "<foo>Hello World!</foo>" ) );
            int eventType = xpp.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                if(eventType == XmlPullParser.START_DOCUMENT) {
                    System.out.println("Start document");
                } else if(eventType == XmlPullParser.START_TAG) {
                    System.out.println("Start tag "+xpp.getName());
                } else if(eventType == XmlPullParser.END_TAG) {
                    System.out.println("End tag "+xpp.getName());
                } else if(eventType == XmlPullParser.TEXT) {
                    System.out.println("Text "+xpp.getText());
                }
                eventType = xpp.next();
            }
            System.out.println("End document");
        }

结果:

 Start document
 Start tag foo
 Text Hello World!
 End tag foo
 End document
 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,520评论 25 707
  • 综述 在aapt编译apk的过程中,aapt中的XMLNode类会将资源生成一个ResXMLTree对象,并将其序...
    Jtag特工阅读 2,118评论 1 3
  • 第一次知道“坦白书”一词好像是朋友Z的介绍,刚开始以为马良这个写作者是一画画的,百度了一下,果然是个画画的。 最近...
    扯来扯去扯不出蛋阅读 459评论 0 1
  • 早晨,依然在儿子的读书声中醒来,依然感觉到九月早晨的清凉。沐浴晨风,我在阳台洗衣。感赏由儿子的晨读开启的每一天。 ...
    苇絮轻扬阅读 223评论 13 6
  • 我觉得共情的能力高的人,辨识度和识人的品质很高,使用客体的能力自然也就高,谈判的空间和策略也就更足 我觉得换位思考...
    956d9ce73cd5阅读 247评论 0 0