在 Android 開發上,或多或少都會使用到圖檔、動畫檔、佈局檔......等靜態資源,這些資源稱為 Resource Files。 涉及儲存這些靜態資源的目錄有 res 及 assets 兩個目錄,其中又以 res 目錄最常使用,res 目錄具有嚴格的子目錄結構定義,每個子目錄都有其用途,這表示您不能隨便在 res 目錄底下建立自己想要的目錄結構。 在少數狀況下,如果您真的需要存取原始資源或自訂目錄結構,那麼您就必需將檔案改存放到 assets 目錄中,但必須再次強調,這是非常少見的狀況。

我們可以很直覺的在專案目錄中使用一般的目錄管理方式管理 Resource Files,在程式碼中操作這些檔案也無需任何權限。 當 APP 編譯成安裝檔時,Resource Files 也會一併放到安裝檔裡面,當 APP 解除安裝時,資料也會一併刪除

目錄結構

下面是一個專案目錄層級結構,其中 res 目錄中的子目錄必須使用支援的目錄名稱,每個子目錄都有規定要存放哪些類型的檔案。另外,請注意不能將檔案直接放在 res 根目錄底下。而 assets 目錄就沒有什麼規定,可以當作一般目錄使用。

            
                Project/
                    src/
                        MainActivity.java
                    res/
                        animator/
                        anim/
                        color/
                        drawable/
                        mipmap/
                        layout/
                        menu/
                        raw/
                        values/
                        xml/
                        font/
                    assets/
            
        

有關 res 目錄中的子目錄用途,請參考下表說明。

目錄 資源類型
animator 定義屬性動畫 (Property Animation) 的 XML 檔案。
anim 定義補間動畫 (Tween Animation) 的 XML 檔案。
color 定義不同狀態呈現的顏色列表,為 XML 檔案。
drawable 圖像檔案,例如:PNG、JPG、GIF、XML。
mipmap APP 應用程式啟動圖示檔案。
layout 定義界面佈局的 XML 檔案。
menu 定義選單的 XML 檔案。
raw 用來存放任何形式的檔案,在程式碼可以使用 Resources.openRawResource() 來存取檔案。
values 定義簡單的 Key-Value XML 檔案,例如字串、整數和顏色。
支援的檔案如下:
  • arrays.xml 用於設定資料陣列。
  • colors.xml 用於設定顏色數值。
  • dimens.xml 用於設定尺寸數值。
  • strings.xml 用於設定字串資料。
  • styles.xml 用於設定樣式。
xml 任何運行時讀取的 XML 檔案,在程式碼中可使用 Resources.getXML() 來讀取檔案。
font 字體檔案。

Property Animation VS View Animation

順便一提,Android 動畫分為 Property Animation 及 View Animation 兩大類型,而 View Animation 又分為 Tween animation 及 Frame animation。

類型 檔案位置 說明
Property Animation res/animator/filename.xml 可在設定的時間內修改物件的屬性,例如背景顏色。
Tween animation res/anim/filename.xml 可進行透明度 (Alpha)、大小縮放 (Scale)、位置移動 (Translate) 及旋轉 (Rotate) 等動畫操作。
Frame animation res/drawable/filename.xml 像電影一樣,按順序播放圖像。

Tween animation 只會改變物件的畫面繪製,而不會改變物件的實際屬性。舉個例子,例如有一個寬高為 50dp 的按鈕,經過 Tween animation 放到兩倍後,由於 Tween animation 不會改變物件的實際屬性,因此按鈕實際可以點擊的範圍還是 50dp。

此外,Tween animation 只能進行透明度 (Alpha)、大小縮放 (Scale)、位置移動 (Translate) 及旋轉 (Rotate) 等動畫操作,超出此範圍 Tween animation 就無能為力了,需要改用 Property Animation。

讀取 res 檔案

res 目錄使用上,需要根據檔案的用途,將檔案放到特定的子目錄當,之後就能在程式碼中使用系統自動生成的 R 類別來存取這些檔案,而這也是唯一能存取 res 檔案的方法。 如果您要使用的檔案沒有適合存放的子目錄,那麼您可以存放在 res/raw 目錄底下,並使用 getResources().openRawResource() 來存取檔案。 另外,請不要將同檔名不同副檔名的檔案放在同一個目錄中,否者編譯時系統會顯示重複資源的錯誤訊息。

讀取

下面是一個讀取 /res/raw/test.json 檔案的範例。

                
                    public String readFileFromResources(int id) throws IOException {
                        InputStream inputStream = getResources().openRawResource(id);
                        BufferedInputStream bufferedStream = new BufferedInputStream(inputStream);
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        for (int result = bufferedStream.read(); result != -1; result = bufferedStream.read()) {
                            outputStream.write((byte) result);
                        }

                        // 關閉串流
                        inputStream.close();

                        // 回傳檔案字串
                        return outputStream.toString("UTF-8");
                    }

                    String string = readFileFromResources(R.raw.test);
                
            
  • 行 2:讀取 res/raw 目錄中的檔案,請使用 getResources().openRawResource()。
  • 行 16:將檔案中的文字讀取放到 string 變數,之後只要將這個變數解析成 JSONObject 或 JSONArray 物件就能直接使用。

讀取 assets 檔案

使用 assets 目錄並沒有太多的限制,可以隨意建立任何目錄層級,就當作一般資料夾使用即可,在程式碼中可使用 getAssets().open() 來存取檔案。 getAssets() 還提供了 openFd() 及 openNonAssetFd() 來讀取檔案,但使用上必需確保要讀取的檔案不能進行壓縮,否者就會拋出 java.io.FileNotFoundException 例外。 但這其實很難確保,因為只要放在 assets 目錄的檔案容量太大,在編譯成安裝檔時,就會自動被壓縮,因此建議盡量少用 openFd() 及 openNonAssetFd(),在 Google 官方文件也是不建議使用。

讀取

下面是一個讀取 /assets/json/test.json 檔案的範例。

                
                    public String readFileFromAssets(String fileName) throws IOException {
                        InputStream inputStream = getAssets().open(fileName);
                        BufferedInputStream bufferedStream = new BufferedInputStream(inputStream);
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        for (int result = bufferedStream.read(); result != -1; result = bufferedStream.read()) {
                            outputStream.write((byte) result);
                        }

                        // 關閉串流
                        inputStream.close();

                        // 回傳檔案字串
                        return outputStream.toString("UTF-8");
                    }

                    String string = readFileFromAssets("json/test.json");
                
            
  • 行 2:讀取 assets 目錄中的檔案,請使用 getAssets().open()。與讀取 res 檔案的程式碼相比,只差在這一行而已。
  • 行 16:將檔案中的文字讀取放到 string 變數,之後只要將這個變數解析成 JSONObject 或 JSONArray 物件就能直接使用。

關於寫入及刪除檔案

無論是 res 或 assets 目錄,您都無法在程式碼中寫入或刪除這兩個目錄中的檔案,這兩個目錄都只能讀取而已。 此外,也沒有任何方法可以直接取得這兩個目錄的路徑,您只能透過 getResources() 及 getAssets() 來存取這兩個目錄中的檔案。