ResourceManager 與資源解析流程
intro
在 Android 開發中,我們最常接觸的並非直接操作底層系統,而是透過資源 (Resources) 與應用進行互動。無論是字串、圖片、佈局、樣式、顏色,甚至是配置 (Configuration) 對應的資源選擇,都仰賴 Android 的 ResourceManager 進行載入與管理。
對開發者來說,資源管理似乎只是「在 res/ 放檔案,然後用 R.xxx 存取」這麼簡單。但對 Android Framework 而言,資源管理其實是 編譯期 → 打包期 → 運行期 三個階段的完整流程,涵蓋了 AAPT 編譯、資源 ID 生成、APK 中資源表的建構,以及運行時依據螢幕大小、語言、夜間模式等條件進行資源解析 (Resource Resolution)。這個系統保證了 Android 能適配全球各種裝置、地區與語言。
資源管理的重要性
為什麼 Android 要有專屬的資源管理系統?理由如下:
- 跨語言與地區支持 (Internationalization)
- 使用 res/values-zh/strings.xml 與 res/values-en/strings.xml,即可針對中文與英文提供不同字串。
- ResourceManager 會依照使用者系統語言自動選擇。
- 跨螢幕與裝置配置支持 (Configuration Qualifiers)
- 針對 hdpi/, xhdpi/, land/, sw600dp/ 目錄提供差異化資源。
- 適應平板、手機、可折疊裝置。
- 權限與安全性
- 資源表會進行 ID 壓縮與優化,避免直接暴露檔案結構。
- ResourceManager 提供 API 層的統一存取,而非直接透過檔案系統。
- 效能與快取
- 運行時 ResourceManager 會快取常用資源,減少 I/O 開銷。
- 與 AssetManager 整合,支持 Memory Mapping 加快存取速度。
資源生命週期:從編譯到運行
Android 的資源處理可分為三個階段:
- 編譯期 (Compile Time)
- 使用 AAPT2 (Android Asset Packaging Tool 2) 將 res/ 資料夾中的 XML、圖片等資源進行編譯。
- XML 轉換為二進位格式 (Binary XML)。
- 生成 R.java 或 R.class,將資源對應到整數 ID。
- 資源 ID 存放在 resources.arsc (資源索引表)。
- 打包期 (Packaging)
- APK 內含:
- /res/ → 原始或壓縮資源檔案。
- /resources.arsc → 資源 ID 與對應的資源項目。
- /assets/ → 直接提供應用讀取的檔案,不會進入資源表。
- 運行期 (Runtime)
- ResourceManager 與 AssetManager 負責載入資源。
- 根據 Configuration (如 locale=zh-TW, density=xxhdpi, orientation=landscape) 選擇最合適的資源。
- 若無法匹配,會 fallback 至 default 目錄。
res/values/strings.xml → (AAPT2) → R.java → 編譯進 APK
res/drawable/icon.png → (壓縮/打包) → resources.arsc
APK 安裝 → ResourceManager 初始化 → 運行期資源解析
ResourceManager 與 AssetManager 的關係
- ResourceManager
Framework 中的核心類別,應用透過 Context.getResources() 取得。
負責:
- 提供 API:如 getString(), getDrawable(), getColor()
- 管理資源快取
- 處理 Configuration 更新 (如系統語言切換)
- AssetManager
- 底層實作類別,負責與 APK 的 resources.arsc、資源檔案交互。
- 提供原始檔案存取,透過 memory-mapped I/O 加快讀取。
應用程式
|
v
Context → ResourceManager → AssetManager → APK 資源表 / 檔案
資源解析流程 (Resource Resolution)
資源解析是 ResourceManager 的核心,流程如下:
- 應用請求資源
- 例:context.getResources().getString(R.string.app_name)
- ResourceManager 查找資源 ID
- 從 R.string.app_name 得到整數 ID。
- 交給 AssetManager 查詢對應資源表。
- Configuration 匹配
- 比對系統當前 Configuration (如 locale=zh, screenDensity=xxhdpi)。
- 在 resources.arsc 中找出最適合的資源版本。
- 回傳結果
- 若是文字,返回字串。
- 若是圖片,返回 Drawable 物件。
- 若找不到,會回退至預設資源 (default resources)。
請求資源 ID
↓
檢查 Configuration (語言、密度、螢幕方向)
↓
是否有對應資源?
├─ 是 → 返回對應資源
└─ 否 → 回退至 default
Configuration 與資源多樣性
- ResourceManager 支持根據不同裝置特性提供差異化資源。常見的 Configuration Qualifiers 包含:
- 螢幕方向:res/layout-land/ vs res/layout-port/
- 螢幕大小與最小寬度:res/layout-sw600dp/
- 螢幕密度:res/drawable-mdpi/, drawable-xxhdpi/
- 語言與地區:res/values-en/, res/values-zh-rTW/
- 夜間模式:res/values-night/
這讓 Android 能在不同裝置與地區,提供在地化與最佳化的體驗。
資源快取與效能優化
為了避免重複解析資源造成效能浪費,ResourceManager 實作了快取機制:
- Drawable 快取
- 字串快取
- Configuration 變更時清理
- 如語言切換、螢幕旋轉,會觸發 ResourceManager 清除快取並重新載入資源。
questions
- 為什麼 getResources().getDrawable() 會回傳不同結果?
- 取決於當前 Configuration,例如夜間模式下可能載入 drawable-night。
- 為什麼 APK 體積很大?
- 如何減少資源浪費?
- 使用 density split 拆分 APK。
use cases
- 多國語系
- 使用 res/values-zh/ 與 res/values-en/ 提供不同字串。
- ResourceManager 自動依照系統語言載入。
- 平板專用佈局
- 在 res/layout-sw600dp/ 定義平板 UI。
- 手機仍使用 res/layout/。
- 夜間模式
- 使用 res/values-night/ 提供不同顏色主題。
Summary
ResourceManager 是 Android Framework 的基礎元件,負責將編譯後的資源表與 APK 中的實際檔案連結起來,並根據裝置的 Configuration 自動進行最合適的選擇。其運作流程從 編譯 (AAPT2)、打包 (APK)、到 運行時 (Resource Resolution),完整支持了多語系、多裝置、多密度與動態配置切換。