零
一、Typedarray幹什麼用的
我們在寫介面佈局的xml時,經常要設定元件的屬性,比如常用的
android:id="@+id/id_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
複製程式碼
而假如我們需要對自定義的view、viewgroup等等新增自定義的屬性呢?就是需要typedarray了。這次我們的例子是給自定義的view新增屬性。
二、怎麼用Typedarray
1.準備一個自定義的view
code警告
public class ViewWithAttrs extends View {
public ViewWithAttrs(Context context, AttributeSet attrs){
super(context, attrs);
}
}
複製程式碼
2.準備(新建)一個arrts.xml
這個xml就是定義屬性的地方,我們開啟之後新增這個<resources>
<declare-styleable name="ViewWithAttrs">
<attr name="paint_color" format="color"/>
</declare-styleable>
</resources>
複製程式碼
注意第二行的name="ViewWithAttrs",name就是你要新增屬性的元件,一定要和view名字相同。
然後就是新增我們想要的屬性了,這裡我新增了一條屬性,屬性名是"paint_color",這個是自己定義的,屬性型別是:color。
還有其他可選的型別有:
reference 表示引用,參考某一資源ID
string 表示字串
color 表示顏色值
dimension 表示尺寸值
boolean 表示布林值
integer 表示整型值
float 表示浮點值
fraction 表示百分數
enum 表示列舉值
flag 表示位運算
3.主角出現:用typedarray獲取xml中的屬性
通過Contex的obtainStyledAttributes方法建立typedarray,然後用getXXX來獲取對應的屬性。
show me the code
public class ViewWithAttrs extends View {
private Paint mPaint;
public ViewWithAttrs(Context context, AttributeSet attrs){
super(context, attrs);
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
//首先通過obtainStyledAttributes方法獲取typedarray
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.ViewWithAttrs);
//使用typedarray獲取對應的屬性
int paintColor = typedArray.getColor(R.styleable.ViewWithAttrs_paint_color, Color.BLACK);
//最後的Color.BLACK是沒獲取到時的預設值
mPaint.setColor(paintColor);
typedArray.recycle();//不要忘記回收!
}
}
複製程式碼
這樣我們獲取到了我們想要的屬性,可以在這個View中使用了
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawCircle(200,200,50,mPaint);
}
複製程式碼
4.等等,我們還沒設定好屬性
在MainActivity的佈局檔案activity_main.xml中新增我們的view並設定好屬性
<com.idealcountry.test.ViewWithAttrs
android:id="@+id/id_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:paint_color="@color/blue"/>
複製程式碼
這樣我們就能在程式碼中獲取xml設定好的paint_color了。//這裡我在color.xml中註冊了一個顏色:color/blue
結果圖:
三、最後一點思考
AttributeSet的問題
小德我在寫自定義的View時,剛開始定義了一個類的屬性用來儲存從AttributeSet獲取的typedarray,但是手滑了把獲取typedarray寫到了onDraw()方法裡了,測試的時候後發現沒有成功獲取到xml中定義的屬性,通過debug這才知道在onDraw方法中拿到的值是空的,採用了預設值。但是這是為什麼呢?
經過查詢到layoutInflater這個類才清楚,大概意思就是AttributeSet並不是每個View都分配一個,而是有類似於快取一樣的機制,大家是共用的(大概可以這麼理解),所以到ondraw就有可能獲取到了不是我們需要的AttributeSet了。
typedarray回收?不存在的
為什麼一定要強調回收呢?這東西又不是佔了執行緒,我就不回收能怎麼樣?(其實不回收的話AS也會一直煩你,說你沒有回收)
為了弄清楚,我們需要進入原始碼來看一看。幾次goto declaration,我們最終在Typedarray.java中找到了,注意這個靜態方法裡的第一句。
static TypedArray obtain(Resources res, int len) {
TypedArray attrs = res.mTypedArrayPool.acquire();
if (attrs == null) {
attrs = new TypedArray(res);
}
attrs.mRecycled = false;
// Reset the assets, which may have changed due to configuration changes
// or further resource loading.
attrs.mAssets = res.getAssets();
attrs.mMetrics = res.getDisplayMetrics();
attrs.resize(len);
return attrs;
}
複製程式碼
而且這個類的構造方法隱藏了,是protected的,很明顯的一個單例模式。
/** @hide */
protected TypedArray(Resources resources) {
mResources = resources;
mMetrics = mResources.getDisplayMetrics();
mAssets = mResources.getAssets();
}
複製程式碼
這樣就清楚了,typedarray是我們在靜態方法Typedarray.obtain中獲取的,是從一個Typedarray池中取出來。不難理解,我們在view中使用typedarray,view會隨著activity的create而create,這樣我們總不能每次都new一個typedarray出來,所以採用了使用typedarray池來管理。這也就是官方一直強調,用完後要衝水,啊不是,用完後一定要回收。
O了個快速排序K
//作為Android開發的初學者,如果我有錯誤的地方或者不足的話歡迎大家指正。希望與大家一同進步