2011-08-06

Android resources 筆記

位於 res 目錄的檔案都稱為 Android resources,依檔案格式可以有圖片(drawable)、xml(anim, layout, menu, values, xml)、其他任意格式(raw),可分別從子目錄名稱知道其用途。

Resource 參照語法

XML 設定檔裡 resource id 的定義語法:

@[package:]type/name

package 目前有兩種用法,第一種是略過 package 不指定,也就是指向該 Android application 的 R.java,第二種是使用 android:,表示使用 android.R.java。


如果是在 drawable 或 layout 目錄下,那麼 type 就是 drawable 或 layout,name 就是其檔案名稱(去掉副檔名);如果是在 values 目錄下, type 就是 id 或 string 等,name 就是其指定的名稱。

舉例說明:
  • @id/text - 表示使用已經定義存在叫做 text 的 id,如果不存在則出錯。
  • @android:id/text - 表示使用 android 定義存在叫做 text 的 id,如果不存在則出錯。
  • @+id/text - 建立一個名為 text 的 id,如果已經有該 id 存在,則直接使用之。
上述第一與第三範例,如何預先定義 id 供稍後使用?
<resources><item type="id" name="text"/></resources>
要小心 name 的使用,xml 支援「-」作為屬性值,但是不能作為 java 變數名稱,所以 name 的使用必須符合 java 變數名稱的使用規則。

編譯 Resource 檔案

只要是 res 裡的檔案都會有 i18n 的效果。

res 裡的檔案可以分成 xml 與非 xml 兩類:
  • xml 檔案也可以分成兩類:
    • 一是像 layout 或 string 這類直接拿來用的 xml 檔案(/res/layout 之類)。
    • 另一種是單純轉成 binary 的 xml 檔案(/res/xml),一般是自訂 xml 格式的檔案,可以用 Android 提供的 xml reader 來讀取。
  • 非 xml 檔案如圖片、聲音、影片等多媒體檔案。
  • 最後是不需要轉成 binary 但要 i18n 效果的檔案可以放在 /res/raw 下,得自行使用一般檔案讀取方式讀取。

字串(string)

位於 res/values 目錄下,不限制檔案名稱,只要是 xml 檔且內容結構為 <resources><string name="...">...</string></resources> 即視為字串,一般都是用 strings.xml,也可以有多個字串 xml 檔案。

可以在 gen/.../R.java 裡找到對應的 resource id,可以在 xml 裡用 R.string.<string標籤裡的name值> 來參考該字串,也可以在程式裡使用 getString(int R.string.id) 來讀取該字串。

R.string.<...> 其型別為 int,並非 String,事實上所有 resource 的型別都是 int,所以在 Android API 裡,可以接受 String 型別的 method 多半都會有另一個接受 int 型別的 method,也就是 resource id。

不管有幾個 resource 檔案,一個 Android application 只會有一個 R.java。

要在字串裡使用單引號有兩種方法,第一種是整個字串用雙引號包起來,第二種方法是 escape 單引號。

要在字串裡使用雙引號只有一種方法,就是 escape 雙引號。

可以在字串裡使用文字相關的 html 標籤,如 <b> 或 <i>,可以使用 setText(int R.string.id) 或者直接在 xml 裡使用 android:text="@string/html_string",不可以使用 getString(int R.string.id),html 標籤會失蹤。

也可以使用 java 格式化字串,String.format(this.getString(int R.string.java_format_string), aaa, bbb) 。

Layout resources

不同於字串是 by tag,layout 是 by file,也就是 res/layout/main.xml 相對於 R.layout.main,一個 xml 檔案一個 resource id。

每個畫面都需要一個 layout xml 設定檔。

存取 layout 裡的元件則是用 findViewById(int R.id.<id>),這裡的 id 對應到 xml 設定檔裡的 android:id 所指定的值。

Colors

定義於 /res/values 下的任意檔案,xml 格式為 <resources><color/></resources>,xml 讀取方式為 @color/color_name,java 讀取方式為 getResources().getColor(int R.color.id)。

顏色定義方式為 #ff0000 或 #f00 表示紅色。

可以使用 android.R.color 來使用 Android 內建的顏色。

字串陣列(string array)

定義於 /res/values 下的任意檔案,xml 格式為 <resources><string-array/>< /resources>,讀取方式為 getResources().getStringArray(int R.array.id)。

複數名詞(plurals)

定義於 /res/values 下的任意檔案,xml 格式為 <resources><plurals/>< /resources>,java 讀取方式為 getResources().getQuantityString(int R.plural.id),英文比較用的到,中文應該不用,用來依據數量的不同選用單數名詞(one)或複數名詞(other)。

Dimensions

定義於 /res/values 下的任意檔案,xml 格式為 <resources><dimen/>< /resources>,xml 讀取方式為 @dimen/dimen_name,java 讀取方式為 getResources().getDimension(int R.dimen.id)。

可以使用的單位有 px(像素)、in(英吋)、mm(毫米)、pt(點)、dp(density-independent pixels)、sp(scale-independent pixels)。

圖片(images)

置於 /res/drawable 下的圖片檔,支援 jpg、gif 與 png 等格式,每個檔案代表一個 resource id(去掉副檔名),xml 讀取方式為 @drawable/img_name,java 讀取方式為 getResources().getDrawable(int R.drawable.id),當有同名的檔案時會出錯。

非 Android 格式的 xml 檔

置於 /res/xml 下的 xml 檔,因為位於 res 目錄下,所以可以使用 resource id 讀取,也有 i18n 效果,而且預先編譯成 binary,java 讀取方式為 getResources().getXml(int R.xml.id),範例如下:
StringBuilder sb = new StringBuilder();
XmlResourceParser xrp = this.getResources().getXml(R.xml.apple);
int eventType = xrp.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
    if (eventType == XmlPullParser.START_DOCUMENT) {
        sb.append("***** START_DOCUMENT *****");
    }
    else if (eventType == XmlPullParser.START_TAG) {
        sb.append("\nSTART_TAG > " + xrp.getName());
    }
    else if (eventType == XmlPullParser.END_TAG) {
        sb.append("\nEND_TAG > " + xrp.getName());
    }
    else if (eventType == XmlPullParser.TEXT) {
        sb.append("\nText > " + xrp.getText());
    }
    else {
        sb.append("\nElse > " + eventType);
    }
    eventType = xrp.next();
}
sb.append("\n***** END_DOCUMENT *****");
((TextView) this.findViewById(R.id.xml)).setText(sb.toString());
上述以外的檔案格式

置於 /res/raw 下的任意檔案,每個檔案代表一個 resource id(去掉副檔名),java 讀取方式為 getResources().openRawResource(int R.raw.id),有 i18n 效果,但是沒有編譯成 binary,用於多媒體檔案或一般文字檔。

上述以外且不支援 i18n 的檔案格式

置於 /assets 下的任意檔案,支援多層子目錄,讀取方式為 getAssets().open(String filePath),因為不是 resource,所以沒有 R.java 可以使用,filePath 不包括 /assets。

i18n

事實上,上面用的 i18n 不僅僅是語系的不同,還有螢幕方向、螢幕大小、螢幕解析度等等。

Android 處理 i18n 是以目錄為基準,不像 java 是以檔案為基準,以螢幕方向為例,/res/layout/main.xml 為預設值,/res/layout-port/main.xml 為直向螢幕選用的設定,/res/layout-land/main.xml 為橫向螢幕選用的設定,這三個 main.xml 只會產生一個 R.java,正確地說,是對程式只會有一個 R.java,不會有 R-port.java這樣的東西,程式只管使用 R.java 就好,至於目前螢幕的方向就由 Android 去判斷,然後選用適當的 R.java 給程式就可以了。

沒有留言:

張貼留言