资源访问机制之AttributeSet与TypedArray


ArrbuteSet:解析XML。

AttributeSet与attr属性定义以及styleable之间建立键值对联系。

我们通过setContentView以及loadHeaderFromResource或者addPreferenceFromResource等方法添加xml文件,在http://blog.csdn.net/droyon/article/details/22429191博文中我们介绍了layout资源是如何被加载的,以及layout文件中的元素时如何被解析成具体的View,LinearLayout等View对象的。

其中有如下代码:

 final AttributeSet attrs = Xml.asAttributeSet(parser);  

这里的parser就是XmlResourceParser 。

ArrbuteSet有如下方法:

<View class="android.widget.NumberPicker"
        android:id="@+id/bytes"
        android:layout_width="48dip"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="16dip"
        android:layout_marginRight="16dip"
        android:focusable="true"
style="@+id/Theme.Default"
 android:focusableInTouchMode="true" />

1、获取特定属性

public String getIdArribute():获取id属性对应的字符串,这里返回@+id/bytes。

pubilc String getClassAttribute():获取class对应的字符串,这里返回android.widget.NumberPicker。

public String getStyleAttribute():获取style对应的字符串,Theme.Default

2、操作通用属性

public int getAttributeCount():获取属性的数目,如上返回10.

3、获取特定类型的值。在View初始化获取xml配置的属性时最为常用。

public XXXType  getAttributeXXXTypeValue(int index,XXXType defaultValue)

TypeArray:和AttributeSet进行配合使用,将AttributeSet对象作为参数,TypeArray提供了更为方便的方法获取xml中的配置值。

TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View,
                defStyle, 0);
 final int N = a.getIndexCount();
        for (int i = 0; i < N; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case com.android.internal.R.styleable.View_background:
                    background = a.getDrawable(attr);
                    break;
                case com.android.internal.R.styleable.View_padding:
                    padding = a.getDimensionPixelSize(attr, -1);
                    break;

TypeArray通过Context对象的obtainStyleAttributes方法获得。第一参数为AttributeSet对象,它包含了xml中配置的所有属性。第二个参数为styleable,aapt将styleable编译成一个数组,该数组包含的内容正是styleable所包含的attr属性的集合。


TypeArray类成员变量如下:

public class TypedArray {
    private final Resources mResources;
    /*package*/ XmlBlock.Parser mXml;
    /*package*/ int[] mRsrcs;
    /*package*/ int[] mData;
    /*package*/ int[] mIndices;
    /*package*/ int mLength;
    /*package*/ TypedValue mValue = new TypedValue();

TypedValue包含如下:

/** The type held by this value, as defined by the constants here.
     *  This tells you how to interpret the other fields in the object. */
    public int type;

    /** If the value holds a string, this is it. */
    public CharSequence string;

    /** Basic data in the value, interpreted according to {@link #type} */
    public int data;

    /** Additional information about where the value came from; only
     *  set for strings. */
    public int assetCookie;

    /** If Value came from a resource, this holds the corresponding resource id. */
    public int resourceId;

    /** If Value came from a resource, these are the configurations for which
     *  its contents can change. */
    public int changingConfigurations = -1;

    /**
     * If the Value came from a resource, this holds the corresponding pixel density.
     * */
    public int density;

TypedValue起内部缓冲的作用,mData数组的作用包含了所有指定的styleable属性值。其初始化的地方为:

new TypedArray(this,
                    new int[len*AssetManager.STYLE_NUM_ENTRIES],
                    new int[1+len], len);
AssetManager.STYLE_NUM_ENTRIES = 6.也就是说,每一个styleable中包含的attr属性值,其由6个attr属性描述。

/*package*/ static final int STYLE_TYPE = 0;
    /*package*/ static final int STYLE_DATA = 1;
    /*package*/ static final int STYLE_ASSET_COOKIE = 2;
    /*package*/ static final int STYLE_RESOURCE_ID = 3;
    /*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
    /*package*/ static final int STYLE_DENSITY = 5;
1、TypeArray使用方法:

TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View,
                defStyle, 0);
for (int i = 0; i < N; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
 case com.android.internal.R.styleable.View_contentDescription:
                    mContentDescription = a.getString(attr);
                    break;

2、getString方法流程:

TypeArray.java

public String getString(int index) {
        index *= AssetManager.STYLE_NUM_ENTRIES;
        final int[] data = mData;
        final int type = data[index+AssetManager.STYLE_TYPE];
        if (type == TypedValue.TYPE_NULL) {
            return null;
        } else if (type == TypedValue.TYPE_STRING) {
            return loadStringValueAt(index).toString();
        }

        TypedValue v = mValue;
        if (getValueAt(index, v)) {
            Log.w(Resources.TAG, "Converting to string: " + v);
            CharSequence cs = v.coerceToString();
            return cs != null ? cs.toString() : null;
        }
        Log.w(Resources.TAG, "getString of bad type: 0x"
              + Integer.toHexString(type));
        return null;
    }
a、传进来的index乘以6,因为每一个attr由6个int描述它。乘6代表此attr在styleable编译的数组当中的位置。

b、接着获取该attr所对应的类型type。如果type == TypeValue.TYPE_NULL,说明此处无值,直接返回null。如果type类型为TypeValue.TYPE_STRING,则,调用loadStringValueAt方法获取string并返回。

c、如果前两者都不是,那么就从缓冲区TypeValue中进行加载数据。返回结果是调用TypeValue的convertToString方法。其方法实质是强制类型转换,比如获取一个int值,那么就@加上该int值,转换成字符串返回。
getValueAt方法的作用是吧mData中的数据,复制到临时缓冲区v(TypeValue)中。

private boolean getValueAt(int index, TypedValue outValue) {
        final int[] data = mData;
        final int type = data[index+AssetManager.STYLE_TYPE];
        if (type == TypedValue.TYPE_NULL) {
            return false;
        }
        outValue.type = type;
        outValue.data = data[index+AssetManager.STYLE_DATA];
        outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
        outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
        outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS];
        outValue.density = data[index+AssetManager.STYLE_DENSITY];
        outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
        return true;
    }
我们重点看一下第二步中的loadStringValueAt方法。

private CharSequence loadStringValueAt(int index) {
        final int[] data = mData;
        final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
        if (cookie < 0) {
            if (mXml != null) {
                return mXml.getPooledString(
                    data[index+AssetManager.STYLE_DATA]);
            }
            return null;
        }
        //System.out.println("Getting pooled from: " + v);
        return mResources.mAssets.getPooledString(
            cookie, data[index+AssetManager.STYLE_DATA]);
    }
a、首先获取cookie值,如果cookie小于0,并且mXml对象不为null,则从xml对象中得到String 的值。mXml对象是专门用于解析xml文件的。关于其历程,我们在layout解析历程中有介绍。

其赋值的地方为:

public TypedArray obtainStyledAttributes(AttributeSet set,
                int[] attrs, int defStyleAttr, int defStyleRes) {
            int len = attrs.length;
            TypedArray array = getCachedStyledAttributes(len);

            // XXX note that for now we only work with compiled XML files.
            // To support generic XML files we will need to manually parse
            // out the attributes from the XML file (applying type information
            // contained in the resources and such).
            XmlBlock.Parser parser = (XmlBlock.Parser)set;
            AssetManager.applyStyle(
                mTheme, defStyleAttr, defStyleRes,
                parser != null ? parser.mParseState : 0, attrs,
                        array.mData, array.mIndices);

            array.mRsrcs = attrs;
            array.mXml = parser;

}
如果cookie大于0,则调用mResource.mAssets的getPooledString方法。其意义和mXml差不多。

2、getDrawable方法历程:

public Drawable getDrawable(int index) {
        final TypedValue value = mValue;
        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
            if (false) {
                System.out.println("******************************************************************");
                System.out.println("Got drawable resource: type="
                                   + value.type
                                   + " str=" + value.string
                                   + " int=0x" + Integer.toHexString(value.data)
                                   + " cookie=" + value.assetCookie);
                System.out.println("******************************************************************");
            }
            return mResources.loadDrawable(value, value.resourceId);
        }
        return null;
    }
调用mResource对象的loadDrawable方法。

/*package*/ Drawable loadDrawable(TypedValue value, int id)
            throws NotFoundException {

        if (TRACE_FOR_PRELOAD) {
            // Log only framework resources
            if ((id >>> 24) == 0x1) {
                final String name = getResourceName(id);
                if (name != null) android.util.Log.d("PreloadDrawable", name);
            }
        }

        final long key = (((long) value.assetCookie) << 32) | value.data;
        boolean isColorDrawable = false;
        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
                value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
            isColorDrawable = true;
        }
        Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);

        if (dr != null) {
            return dr;
        }

        Drawable.ConstantState cs = isColorDrawable ? sPreloadedColorDrawables.get(key) : sPreloadedDrawables.get(key);
        if (cs != null) {
            dr = cs.newDrawable(this);
        } else {
            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
                    value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
                dr = new ColorDrawable(value.data);
            }

            if (dr == null) {
                if (value.string == null) {
                    throw new NotFoundException(
                            "Resource is not a Drawable (color or path): " + value);
                }

                String file = value.string.toString();

                if (TRACE_FOR_MISS_PRELOAD) {
                    // Log only framework resources
                    if ((id >>> 24) == 0x1) {
                        final String name = getResourceName(id);
                        if (name != null) android.util.Log.d(TAG, "Loading framework drawable #"
                                + Integer.toHexString(id) + ": " + name
                                + " at " + file);
                    }
                }

                if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
                        + value.assetCookie + ": " + file);

                if (file.endsWith(".xml")) {
                    try {
                        XmlResourceParser rp = loadXmlResourceParser(
                                file, id, value.assetCookie, "drawable");
                        dr = Drawable.createFromXml(this, rp);
                        rp.close();
                    } catch (Exception e) {
                        NotFoundException rnf = new NotFoundException(
                            "File " + file + " from drawable resource ID #0x"
                            + Integer.toHexString(id));
                        rnf.initCause(e);
                        throw rnf;
                    }

                } else {
                    try {
                        InputStream is = mAssets.openNonAsset(
                                value.assetCookie, file, AssetManager.ACCESS_STREAMING);
        //                System.out.println("Opened file " + file + ": " + is);
                        dr = Drawable.createFromResourceStream(this, value, is,
                                file, null);
                        is.close();
        //                System.out.println("Created stream: " + dr);
                    } catch (Exception e) {
                        NotFoundException rnf = new NotFoundException(
                            "File " + file + " from drawable resource ID #0x"
                            + Integer.toHexString(id));
                        rnf.initCause(e);
                        throw rnf;
                    }
                }
            }
        }

        if (dr != null) {
            dr.setChangingConfigurations(value.changingConfigurations);
            cs = dr.getConstantState();
            if (cs != null) {
                if (mPreloading) {
                    if (isColorDrawable) {
                        sPreloadedColorDrawables.put(key, cs);
                    } else {
                        sPreloadedDrawables.put(key, cs);
                    }
                } else {
                    synchronized (mTmpValue) {
                        //Log.i(TAG, "Saving cached drawable @ #" +
                        //        Integer.toHexString(key.intValue())
                        //        + " in " + this + ": " + cs);
                        if (isColorDrawable) {
                            mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
                        } else {
                            mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
                        }
                    }
                }
            }
        }

        return dr;
    }




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hailushijie

您的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值