對資源應用做了一些學習,準備從三個方面來描述總結:
1. 整體介紹
2. 資源打包
3. 資源配置&加載
1. 整體介紹
1. 資源類型
針對前面提到的兩個目錄下的各種資源,最終都是經過AAPT打包到APK中。資源打包時,會生成R.java, 提供給應用程序通過ID訪問資源。
res目錄下的文件,除了res/raw外的文件都會進行編譯,編譯成二進制文件輸出,這樣會加速後續資源的訪問。
對於res目錄下的資源,由於都分配了ID, 應用程序可以通過資源ID來訪問。而對於assets目錄下的資源,應用程序通過具體的文件名訪問。
1.2 Android顯示相關的概念
Android應用開發提供資源時需要能適配Android設備的多樣性 。對與Android不同的顯示設備,經常使用如下一些概念描述。
分辨率和DP是最常接觸使用的,給定如下一些分辨率與DP轉換示例:
配置1: 1920 x 1080, 480dpi ==> 640dp x 360dp
配置2: 1280 x 720, 320dpi ==> 640dp x 360dp
配置3: 960 x 600, 160dpi ==> 960dp x 600dp
配置4: 1280 x 800, 160dpi ==> 1280dp x 800dp
2. Android資源打包
Android代碼資源分離,採用AAPT單獨對資源編譯打包
AAPT(Android Asset Packaging Tool)
源碼路徑:frameworks/base/tools/aapt/
2. 1 資源打包生成文件
資源編譯打包後,在APK中有res, assets兩個目錄,同時有resources.arsc資源索引文件。
Res目錄中除了raw目錄,其他文件都是編譯過的,另外values會打包到resources.arsc中, 所以打包後的res中沒有values目錄
Resources.arsc是資源索引文件,可以使用Android Studio直接查看, 或者使用aapt l -a > output導出
資源索引表建立ID與資源值/路徑的映射關係
對於layout/drawable等資源, ID映射的值是一個全路徑文件名。資源查找時,拿到的是一個文件名,Resource Framework會再根據文件名打開對應的文件提供給App
對於string等一些資源,ID映射的直接是一個值 ,因此資源查找時直接獲取到App需要的值。
AssetManager基於索引表查找資源
通過Resource ID加載非asset資源
先通過AssetManager查詢resources.arsc中資源ID對應的值
ID對應的如果是一個值,例如value/string值,直接返給應用
ID對應的如果是一個文件名, 需要再通過AssetManager打開文件
通過文件名加載asset資源
直接通過AssetManager打開文件
資源打包的最後過程會生成R.java,裏面給出了所有資源的ID.
提供給程序指定資源ID獲取到對應資源
ID格式4 Byte: [1][1][2] : [package][type][index]
3. 資源配置
關於資源配置,Android developer上有詳細的文檔說明:
https://developer.android.google.cn/guide/topics/resources/providing-resources.html
Android定義了18個維度的配置限定符, App通過配置限定符來提供備用資源。
資源定義時需要按表中順序添加限定符,系統加載資源時也是按表中優先級依次適配資源。
3.1 屏幕尺寸Screen Size限定符
此配置符用於爲不同屏幕尺寸提供不同資源
屏幕尺寸: 四種通用尺寸:小、正常、 大 和超大
Android早期版本多用於適配平板所需資源,但區分不夠精確
使用smallest width, available width, available height替代
3.2 屏幕寬度/高度Available Width /Height限定符
w<N>dp (w720dp, w1024dp)
h<N>dp (h720dp, h1024dp)
應用實際可用空間不是物理屏的size, 需要減去系統永久性UI的空間
豎屏切換時, 可用寬/高會發生轉換
系統會使用最接近(但未超出)設備當前屏幕寬度的值
例如系統檢測到當前應用可用屏幕寬度爲720dp, 則優先匹配w720dp, 如果沒有,則查找小於w720dp的配置
Width對layout的影響更大,使用available height的應用相對較少.
3.3 最小寬度Smallest Width限定符
sw<N>dp (sw320dp,w600dp,sw720dp)
Available Width/Heigh中的最小尺寸
不受屏幕旋轉影響
系統會使用最接近(但未超出)設備 smallestWidth 的值
w/h/sw都是應用的configuration, 是Activity實際可用的空間
Freeform模式下,應用窗口大小可以自由縮放,所以在縮放過程中會觸發configuration change, 重新加載適合的資源.
3.4 屏幕像素密度限制符
應用開發時僅僅使用sw/w/h有時候不夠
[1080p 480dpi] 與[720p 320dpi]對應的sw/w/h相同,但可能需要提供不同的圖片資源
應用如果只提供sw<N>dp資源,在小尺寸屏幕或者應用窗口被縮小的情況下,系統可能無法查找到合適的sw限定符資源
sw/w/h沒有反應出屏幕像素密度
引入像素密度限制付: <N>dpi
如果沒有提供最符合當前設備配置的限定符,則系統使用其中最匹配的資源
先大後小的原則匹配
源碼中的算法:
configuration < low < high ==> 選擇low
configuration > high > low ==> 選擇high
low < configuration < high ==> (2 * low – configuration) * high > configuration * configuration ? : low , high
Android系統會根據物理像素密度設定Android系統的像素密度.
3.5 屏幕分辨率限定符
引入screen size的限制符: <N>x<M>
value-1920x1080
適配原則
匹配最接近(但未超出)設備分辨率的值
源碼中匹配算法:
去除超出screen size的資源
使用(w+h)最接近當前configuration.(w+h)的資源
screen size與available width/height的比值爲dpi/160
3.6 限定符組合使用
很多場景需要使用多種限定符的組合來提供合理的資源,如下是隨意列舉的一些配置:
w+h:values-w720dp-h400dp;
sw + dpi:values-sw400dp-xxdpi;
dpi + screen size:values-xxhdpi-1920x1080
4. 資源加載實例
4.1 Layout資源加載
加載原則
1. 按Android定義的18個維度按優先級匹配
2. 某一個維度內,則按當前維度的規則
swxxxdp
優先找最匹配的,然後找低於configuration的swxxxdp
不會匹配高於當前configuration的swxxxdp
Density
優先找最匹配的
然後按先大後小的原則匹配
給定一個配置:1920x1080, 屏幕密度:480dpi, 給定如下一些layout,則加載的優先級如下:
layout-sw360dp
layout-sw240dp
layout-xxhdpi
Layout-xxxhdpi
layout-xhdpi
layout-hdpi
layout-mdpi
4.2 Drawable資源加載
與Layout相同的加載原則:先高後低
假設設備xxhdpi:匹配優先順序爲xxhdpi > xxxhdpi> xhdpi> hdpi> mdpi
爲了保證視覺一致性,系統會再對圖片按比例進行縮放處理
假設設備xxhdpi, 在drawable-mdpi找到圖片,系統認爲你放在mdpi下的圖片可能偏小,所以做了自動放大處理. 放大的倍數爲DPI的比值
此例會放大480/160 = 3倍
影響顯示效果, 佔用內存增大
同樣,如果在drawable-xxxdpi找到圖片,系統認爲圖片偏大,所以自動縮小.
縮小480/640 = 0.75
給定設備:1920x1080, 480dpi. 提供圖片:270 x 480 (屏幕1/4),放置在如下不同drawable-xxx目錄(xxxhdip , xxhdpi, xhdpi, mdpi),將得到不同縮放的視覺效果:
如何保證Drawable的視覺一致性
如果提供多套資源,圖片需要遵循縮放比率
如果提供一套資源,儘量提供高密度的資源
圖片放大比圖片縮小的視覺效果差
4.3 Values目錄
其中有dimen等一些與屏幕顯示相關的配置
values目錄下一般是使用dp進行定義,已經保證了視覺一致性,所以系統不會進行縮放
某些場景希望視覺尺寸不同,則增加values-xxx目錄定義新的值.例如物理尺寸大的平板需要更大的UI顯示