My favorites | Sign in
Logo
                
Search
for
Updated Nov 02, 2009 by gasolin
Labels: tw, XML, Resource
XmlR  
存取識別符號

在上一章談了 XML描述檔中介面元件的各種「android:」開頭的屬性。要使用一個介面元件,第一件事就是定義出介面描述檔。大部分的介面元件(如 LinearLayout、TextView)不需要在程式中作後續處理,因此可以直接描述(例如我們前面定義過的 TextView 文字顯示元件「身高(cm)」)。但對於那些將在程式中被參考(reference)到的介面元件(如按鈕 Button、文字輸入欄位 EditText),我們需要先行在 XML描述檔中,定義該介面元件的「android:id」識別符號屬性。這麼一來在程式碼中我們要操作這個介面元件(取出欄位中輸入的資料、取得按下按鈕事件...)時,就能透過「android:id」識別符號來調用這個介面元件。

<EditText android:id="@+id/height"
    />

前面章節提過,寫作時最好將 XML 描述檔屬性分行列出,以易於閱讀(增加可讀性)。而我們的範例卻將 android:id 屬性直接擺在 EditText 標籤後。其實這麼做同樣是基於易於閱讀的考量。當然你也可以將「android:id」屬性分行列出,或是將「android:id」屬性放在屬性列表的中間或最後頭,這些作法都是允許的,本書中一律採用將 android:id 屬性直接擺在介面元件標籤後的寫法。

android:id 屬性的內容長得比較特別:

@+id/height

「height」是這個介面元件的 android:id。以後的程式中會使用「R.id.height」來取得這個介面元件。「@+id」 的意思是我們可以通過這個識別符號來控制所對應的介面元件,「R」類別會自動配置一個位址給這個介面元件。 「R」類別的內容則可以透過查看 R.java 得知。

XML 描述檔與 R.java 檔

在 Android 系統中,我們使用 XML 來定義 UI。但是有些稍微有經驗的開發者可能會有疑問:

「用 XML 來描述介面固然方便,但是對於手機程式來說,直接用 XML 檔案是不是太占空間了?」。

沒錯,如果 Android 是直接使用 XML 來儲存介面描述到手機上的話,一定會佔用比起現在大的多的檔案空間。解決的方法是Android 並不直接使用 XML 檔案,而是透過 Android 開發工具,自動將 XML 描述檔轉換成資源檔案。一旦應用程式要操作某個介面元件,或是使用任何種類的資源(字串、圖片、圖示、音效...),都使用索引來查詢。

當你建立一個 BMI 新專案,打開位於 「gen/com/demo/android/bmi」 目錄下的 「R.java」檔,你可以看到如下的程式碼:

    /* AUTO-GENERATED FILE.  DO NOT MODIFY.
     *
     * This class was automatically generated by the
     * aapt tool from the resource data it found.  It
     * should not be modified by hand.
     */

    package com.demo.android.bmi;

    public final class R {
        public static final class attr {
        }
        public static final class drawable {
            public static final int icon=0x7f020000;
        }
        public static final class layout {
            public static final int main=0x7f030000;
        }
        public static final class string {
            public static final int app_name=0x7f040000;
        }
    }

在照著前一章新增了 XML 描述後,再次打開打開 「gen/com/demo/android/bmi」 目錄下的 「R.java」 檔 ,你可以看到如下的程式碼:

    /* AUTO-GENERATED FILE.  DO NOT MODIFY.
     *
     * This class was automatically generated by the
     * aapt tool from the resource data it found.  It
     * should not be modified by hand.
     */

    package com.demo.android.bmi;

    public final class R {
        public static final class attr {
        }
        public static final class drawable {
            public static final int icon=0x7f020000;
        }
        public static final class id {
            public static final int height=0x7f050000;
            public static final int result=0x7f050003;
            public static final int submit=0x7f050002;
            public static final int suggest=0x7f050004;
            public static final int weight=0x7f050001;
        }
        public static final class layout {
            public static final int main=0x7f030000;
        }
        public static final class string {
            public static final int app_name=0x7f040000;
        }
    }

我們看到在 R.java 檔案中,分別有 attr (屬性)、drawable (圖片、圖示)、id (識別符號)、layout (介面描述)、string (文字) 這幾種資源型態,就 XML 描述檔中的 id 來說,開發工具會根據 XML 描述檔中指定的 id,生成對應的資源,並自動指定一個位址。

Google 官方文件是這麼解釋「R.java」檔案的作用的:

A project's R.java file is an index into all the resources defined in the file. 
You use this class in your source code as a sort of short-hand way to refer to 
resources you've included in your project. This is particularly powerful with the 
code-completion features of IDEs like Eclipse because it lets you quickly and 
interactively locate the specific reference you're looking for.

The important thing to notice for now is the inner class named "layout", and 
its member field "main". The Eclipse plugin noticed that you added a new XML 
layout file and then regenerated this R.java file. As you add other resources to 
your projects you'll see R.java change to keep up.

有了「R.java」做中介,在 XML 描述檔中,我們可以透過

@[類型]/[識別符號]

這樣的語法來為某個介面元件提供識別符號,以供程式控制。

例如,我們可以用 「@+id/height」來為對應供輸入身高數字的 EditText 元件提供識別符號。

將字串抽離 XML

當我們在 res 資料夾中新增各種一個 XML 檔案,或是一張圖片時,開發工具會從 res 資料夾中蒐集,並將各種資源彙整成一個索引,自動產生出 R.java 檔。

透過這個特性,我們可以進一步加工我們的 XML 描述檔,讓介面更易於維護。

開啟 res/values/strings.xml

原始的內容為

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">BMI</string>
</resources>

裡面只定義了一個字串「app_name」,用來表示應用程式名稱(在之後講解 AndroidManifest.xml 檔案時將會用到)。 我們看到表示字串的格式為

<string name="識別代號">文字敘述</string>

我們將上一章中的敘述抽取出來,整理進 strings.xml 檔案。

完整的 strings.xml 檔案如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">BMI</string>
    <string name="bmi_height">身高 (cm)</string>
    <string name="bmi_weight">體重 (kg)</string>
    <string name="bmi_btn">計算 BMI 值</string>
    <string name="bmi_result">你的 BMI 值是 </string>
</resources>

在 strings.xml 檔案中,我們在原本的 app_name 字串外,自行定義了另外幾個字串。如果我們再次開啟 「R.java」檔,我們會發現檔案中的 string 類別中也自動索引了上面定義好的字串:

    public static final class string {
        public static final int app_name=0x7f040000;
        public static final int bmi_btn=0x7f040003;
        public static final int bmi_result=0x7f040004;
        public static final int bmi_height=0x7f040001;
        public static final int bmi_weight=0x7f040002;
    }

接著,我們把這些字串應用到之前定義好的 XML 描述檔中。透過使用

@string/[識別符號]

這樣存取 string 類型的格式,來取代 main.xml 檔案中原本寫死的文字敘述。

完整的程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
	<TextView 
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="@string/bmi_height"
	    />
	<EditText android:id="@+id/height" 
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:numeric="integer"
	    android:text=""
	    />
	<TextView 
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="@string/bmi_weight"
	    />
	<EditText android:id="@+id/weight" 
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content"
	    android:numeric="integer"
	    android:text=""
	    />
	<Button android:id="@+id/submit" 
	    android:layout_width="wrap_content" 
	    android:layout_height="wrap_content" 
	    android:text="@string/bmi_btn"
	    />
        <TextView android:id="@+id/result"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text=""
             />
	<TextView android:id="@+id/suggest" 
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text=""
	    />
</LinearLayout>

再次運行 Android 虛擬機器,我們看到與前一節完全相同的介面。但就介面而言,透過將描述字串統一集中在 「string.xml」 中,我們以後要修改介面時更有彈性了。

至此我們已經完成了 BMI 應用程式負責「顯示 (View)」的部份。

新增 XML 檔案

我們在前面都只修改到開發工具幫我們產生的檔案, 而事實上,我們所有在 「res」 目錄中所做的修改,開發工具都會自動搜尋,將之整理到「R.java」中。因此我們也可以在「src/values」中建立自己的文字描述檔案。

我們這就在「res/values」目錄中建立一個 「advice.xml」檔,裡面將包含 BMI 程式算出 BMI 值後將給予的建議文字,完整的檔案如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="advice_light">你該多吃點</string>
    <string name="advice_average">體型很棒喔</string>
    <string name="advice_heavy">你該節食了</string>
</resources>

打開「R.java」檔,我們發現「advice_light」、「advice_average」、「advice_heavy」也已整理進「R.java」檔的索引中,以供程式調用。

Android 中所有的資源檔案(圖片、XML等)命名都必須使用英文小寫,檔名中間只允許加上底線「」符號。其他的檔名都會造成無法正常產生R.java 檔,讓你的程式無法編譯。

那麼接下來,我們就開始進入到了解 Android 程式流程的部分吧。

< 設計使用者介面 | 回目錄 | 解讀程式流程 >


對於本章,您還期望知道什麼樣的內容呢?請在下方提出建議!


Comment by b9507017, Jan 18, 2009

我在新增XML檔案的時候卡住還久的,不知道怎麼新增,也許這邊可以補充講解說明一下新增辦法。謝謝

Comment by ctin.rma.taiwan, Jan 20, 2009

我是在values資料夾上用滑鼠右鍵New-->file,file name就打advice.xml。

Comment by Brooke.Gu, Feb 23, 2009

b9507...@mail.ntust.edu.tw, 我的添加方法: values資料夾上用滑鼠右鍵New,在弹出的菜单中选择others,然后在弹出在New对话框中选择XML类型,并输入文件名称后按Finish即可。

Comment by azthomas, May 11, 2009

請問 @id/name 跟 @+id/name 有何差異,謝謝您。

Comment by simonsu.mail, Jun 05, 2009

目前看到xml中都是同一種語言,是否有support多國語言呢? 另外,在Eclipse中按alt+/可以顯示提示,在這邊也有用喔~給大家參考

Comment by gasolin, Jun 10, 2009

simonsu.mail, 支援多國語言, 不想找原文看的話, 在實體書裡有教

Comment by kiwiberry77, Jul 09, 2009

不知為何,我的R.java不會自動配合values/.xml更新耶

Comment by gasolin, Jul 09, 2009

kiwiberry77, 隨便改一下 xml 檔內容, 再 refresh 一下應該就會改變了

Comment by new126r...@126.com, Sep 28, 2009

<EditText? android:id="@+id/height"

...... />
与 <TextView? ...
android:text="@string/height"
/>
文字显示文本输入框 标识与引用都是 height 有点要弄混、晕乎乎的感觉

Comment by gasolin, Sep 28, 2009

一個是 id, 一個是 string 呀, 兩者在不同分類下. 簡單地說, string 是預先定義好的字串拿過來用的, id 是定義給程式碼呼叫的. id 後面接的是在這個檔案中預先定義給程式操控的參數, string 後面接的是從 res/values 目錄的 xml 檔案中預先定義的字串代號.

Comment by new126r...@126.com, Sep 29, 2009

这个我知道,就好象有个天天在一起的同事和单位门岗养的狗叫相同名字一样,反正觉得怪怪的,当然能分开,有工作不会叫上狗一起做,从饭店带回来的剩饭菜不会让同事吃

Comment by gasolin, Sep 29, 2009

這麼說有道理, 改了 :)

Comment by huzshih, Oct 07, 2009

不好意思請問:R.java不是在gen裡面嗎?文中好像是說src呢??

Comment by gasolin, Oct 07, 2009

huzshih, 是的, 1.5 版之後 R.java 從 src/ 換到 gen/ 了, 謝謝指正


Sign in to add a comment
Hosted by Google Code