试管代孕妈妈怎么找?

█13★710097773█  电微信同号 █供卵试管婴儿██代孕选性别生男孩 ██试管包出生██代孕男孩██代孕包出生███代孕选性别██试管婴儿███代孕生男孩█████试管婴儿代孕生男孩███供卵试管婴儿代孕███

在自定义控件的时候,如果我们想额外的添加一些属性,就会用到TypedArray这个类,那么这个类是怎么得到的,以及怎么使用的,这篇讲会详细讲解,下面是我以前自定义控件的一段代码

TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.myaccount_item_style);

我们看到TypedArray是通过Context的方法得到的,但要记住完成之后一定要调用recycle()方法进行回收,我们点进去找到最终实现

public TypedArray obtainStyledAttributes(AttributeSet set,  
        int[] attrs, int defStyleAttr, int defStyleRes) { final int len = attrs.length; final TypedArray array = TypedArray.obtain(Resources.this, 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). final XmlBlock.Parser parser = (XmlBlock.Parser)set; AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes, parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices); array.mTheme = this; array.mXml = parser; …………… return array; }

我们先看下面AssetManager的applyStyle方法是native方法,也就是用C++实现的,他会提取自定义控件属性的的值保存TypedArray中的mData数组中,这个数组的大小是由你定义控件属性的个数决定的,是他的6倍,上面的attrs其实就是你自定义属性的个数,我们来看一下

static TypedArray obtain(Resources res, int len) {  
    final TypedArray attrs = res.mTypedArrayPool.acquire(); if (attrs != null) { attrs.mLength = len; attrs.mRecycled = false; final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES; if (attrs.mData.length >= fullLen) { return attrs; } attrs.mData = new int[fullLen]; attrs.mIndices = new int[1 + len]; return attrs; } return new TypedArray(res, new int[len*AssetManager.STYLE_NUM_ENTRIES], new int[1+len], len); }

他首先会从TypedArray池中获取,如果有就取出,mDate的大小不能小于属性个数的6倍,因为STYLE_NUM_ENTRIES的值为6,如果没有就new一个然后返回,把属性的值提取出来之后我们就可以来操作了,我们先来看一下View类初始化中的一段代码

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; ………………… } }

他会把TypedArray中的数据提取出来对View的属性赋值,我们来看一下TypedArray类的构造方法

/*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {  
    mResources = resources;  
    mMetrics = mResources.mMetrics;  
    mAssets = mResources.mAssets;  
    mData = data;  
    mIndices = indices;  
    mLength = len;  
}

代码很简单,其中mData就是就是从xml文件中提取到的数据,mData的大小是自定义属性个数的6倍,所以这里是每6个作为一组,我们可以看一下上面的obtain方法中data数组的大小是乘以6(STYLE_NUM_ENTRIES)的,这6种类型如下,定义在AssetManager类中,下面的第一个表示每组6个

/*package*/ static final int STYLE_NUM_ENTRIES = 6;  
/*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;

对应着TypedValue类中的这7中类型,其中string是根据type得到的

/** 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;

如果我们认真看的时候就会发现obtain方法中对mIndices数组初始化的时候是加1的,因为mIndices数组的第一个保存的是我们所使用属性的个数,记住是使用不是定义,我们来看一下其中的一些代码

/** 
 * Return the number of values in this array. 
 */  
public int length() { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } return mLength; } /** * Return the number of indices in the array that actually have data. */ public int getIndexCount() { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } return mIndices[0]; }

第一个length返回的是我们所定义属性的个数,因为这个参数是在构造函数中赋值的,传递的是int[] attrs的长度,而这个sttrs就是我们在attrs文件中自定义属性的时候在R文件中自动生成的一个数组。而下面的getIndexCount()方法返回的是我们所使用的属性个数,因为mIndices的数据是从xml文件中提取的,第一个位置保存的是我们使用属性的个数,后面的位置就是我们使用的自定义属性在R文件中生成的id,在看一个方法,也是自定义的时候常用到的

public int getIndex(int at) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } return mIndices[1+at]; }

这个得到的就是自定义属性在R文件中生成的id,剩下的一些方法就是从TypedArray中提取值了,主要有以下几种类型

<declare-styleable name="CustomTheme">  
    <attr name="textView1" format="string" /> <attr name="textView2" format="boolean" /> <attr name="textView3" format="integer" /> <attr name="textView4" format="float" /> <attr name="textView5" format="color" /> <attr name="textView6" format="dimension" /> <attr name="textView7" format="fraction" /> <attr name="textView8" format="reference" /> <attr name="textView9" format="enum" /> <attr name="textView10" format="flags" /> </declare-styleable>

TypedArray方法比较多,这里就捡常用的几个来分析一下,在分析之前先看一下下面这个方法

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; } return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]); }

上面所说的每6个一组,其中每组下标为STYLE_ASSET_COOKIE(2)的是用来标记缓存的,并且是只对String类型的,我们来看一下

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

上面这个方法是把mData指定范围的6个数据提取到outValue中,其中string值通过type类型得到的,我们再来看一下assetCookie的注释

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

所以他只针对String类型,我们再来看一下String类型的注释

/** The <var>string</var> field holds string data.  In addition, if 
 *  <var>data</var> is non-zero then it is the string block 
 *  index of the string and <var>assetCookie</var> is the set of 
 *  assets the string came from. */  
public static final int TYPE_STRING = 0x03;

所以他只针对string类型的数据进行提取,比如text,String,color等,color可以是string类型也可以是int类型,还看上面的loadStringValueAt方法,如果cookie小于0,说明没有缓存,就会从xml中解析,否则就从缓存中取

/*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) { // Cookies map to string blocks starting at 1. return mStringBlocks[cookie - 1].get(id);

我们来看一下是怎么从xml中解析的,看到上面的obtainStyledAttributes方法,会发现这样一段代码 array.mXml = parser;其中parser就是View及其子类在初始化的时候传递的AttributeSet,我们在前面的《Android LayoutInflater源码分析及使用(二)》中讲到,View及其子类创建的时候是通过反射来初始化的,我们来回顾一下

public final View createView(String name, String prefix, AttributeSet attrs)  
         throws ClassNotFoundException, InflateException {  
     Constructor<? extends View> constructor = sConstructorMap.get(name);  
     Class<? extends View> clazz = null; try { ………………………… constructor = clazz.getConstructor(mConstructorSignature); ………………………… Object[] args = mConstructorArgs; args[1] = attrs; constructor.setAccessible(true); final View view = constructor.newInstance(args); ………………………… return view; } catch (NoSuchMethodException e) { ………………………… } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }

其中attrs是通过Resource的loadXmlResourceParser方法加载的,我们看一下

/*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)  
        throws NotFoundException {  
    synchronized (mAccessLock) {  
        TypedValue value = mTmpValue; if (value == null) { mTmpValue = value = new TypedValue(); } getValue(id, value, true); if (value.type == TypedValue.TYPE_STRING) { return loadXmlResourceParser(value.string.toString(), id, value.assetCookie, type); } throw new NotFoundException( "Resource ID #0x" + Integer.toHexString(id) + " type #0x" + Integer.toHexString(value.type) + " is not valid"); } }

剩下的就是涉及到Xml的解析,这里就不在作深入探讨,言归正传,还回到刚才的loadStringValueAt方法,如果缓存中存在就从缓存中去,如果不存在就通过xml解析获取。下面在看一下一些常用的方法,其中getText(int index)和getString(int index)差不多,我们就来看一下getString(int index)方法

public String getString(int index) {  

猜你喜欢

转载自www.cnblogs.com/dujiaCC/p/10940792.html