標籤:
更新: 對於自訂屬性資源,現在不實用http://schemas.android.com/apk/res/<Packge name> 的形式了, 統一用
"http://schemas.android.com/apk/res-auto"
Android應用程式將所有的靜態資源都封裝在了APK檔案中,並根據這些資源檔名(不包括副檔名)或key屬性的值產生資源ID。這些ID將作為變數的形式被定義在R類的相應子類中。例如,所有的映像資源(res/drawable目錄中的資源檔)都會在R.drawable類中產生相應的變數,變數名就是映像資源的檔案名稱。當使用這些資源時,只要引用R類中相應的變數,系統就會知道上哪去尋找相應的資源。大多數資源的定位很好理解,例如,"@string/hello"引用了字串資源hello。"@drawable/icon"引用了映像資源檔(可能是icon.png、icon.jpg等映像)。但有一類資源的引用可能大多數初學者不太注意,這就是屬性資源。
為瞭解釋屬性資源,現在先來看一段<TextView>標籤的定義代碼。
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"/>
在這段代碼中設定了android:layout_width和android:layout_height屬性,我們會發現,如果將android:layout_width改成android:layout_width1,一定是無法編譯通過的。而如果不加android命名空間,可以任意設定<TextView>標籤的屬性,只要屬性和屬性值符合XML規範,就可以編譯通過。例如,下面的<TextView>標籤設定了test屬性後,完全可以進行正常編譯。
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" test="value"/>
從這一點可以判斷,系統對android:layout_width屬性的驗證與XML本身無關。那麼到底與什麼有關呢?
實際上,android:layout_width要分開來看,首先看layout_width。系統內部有一個系統級的R.java檔案,所有的系統資源產生的ID都在該檔案中的R類相關子類中定義。而在這個R類中有一個attr子類,用於定義系統中所有的屬性,也就是XML標籤設定的屬性名稱,而這個R類的Package就是android。
我們並不需要去關心R類的代碼,因為這個R類是在Android原始碼編譯時間自動產生並編譯的,Android原始碼和Android SDK中並沒有這個R類的原始碼。不過讀者可以隨便找一個Android工程,選擇Android 4.2開發包(也可以是其他版本),很容易就可以找到R類及其attr子類,8-12黑框中所示。
在attr類中有很多我們已經很熟悉的成員變數,例如,layout_width、layout_height就是attr類中的兩個變數。那麼這個屬性資源有什麼用呢?
系統在檢測XML標籤屬性時,如果可以確定某一個R類的位置,就會認為當前XML標籤的屬性名稱必須與R.attr類中某個變數名一致,否則會認為該屬性有誤。那麼系統又是如何確定R類的位置呢?
答案當然是android命名空間了,也就是說android命名空間會直接指定這個內嵌在系統中R類的位置。下面看一下android命名空間的定義。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ……> …… </RelativeLayout>
我們可以看到,android命名空間的值是一個Url形式的字串,不過這個Url是有一定規則的。這個Url的通用形式如下:
http://schemas.android.com/apk/res/<Package Name>
也就是說這個Url有一個叫"http://schemas.android.com/apk/res/"的首碼,後面跟的內容就是R類的Package名。結合前面android命名空間的定義可知,Package名就是android。而前面已經提到過,系統內嵌的R類的Package就是android。所以通過這個android命名空間,系統就可以知道R類的全名(Package Name + Class Name),所以就可以直接定位了 。
儘管android命名空間的值不能修改,不過android命名空間的名稱是可以修改的,例如,下面的<TextView>標籤的設定是合法的。
<RelativeLayout xmlns:mobile="http://schemas.android.com/apk/res/android" ……> <TextView mobile:layout_width="wrap_content" mobile:layout_height="wrap_content"/> </RelativeLayout>
假設在當前應用程式中R類的Package是www.mobile.com,並且要引用R類中屬性資源,那麼命名空間應該按如下方式設定。
<RelativeLayout xmlns:mobile="http://schemas.android.com/apk/res/www.mobile.com" ……> …… </RelativeLayout>
當然,屬性資源還不僅僅能限制屬性名稱,還可以約束屬性值,
屬性資源與Android命名空間