Android應用資源—提供資源(Providing Resources)(三)

使用資源提供最好的設備兼容性

為瞭讓應用程序支持多種設備配置,始終給應用程序使用的每種資源類型都提供默認的資源是至關重要的。

例如,如果應用程序支持幾種語言,就要始終包含沒有語言和區域限定符的values/目錄。如果把所有的字符串文件都放到由語言和區域限定符的目錄中,那麼當應用程序運行在不支持應用程序提供的語言集的設備上時,就會崩潰。但是,隻要提供瞭默認的values/資源,應用程序就會正確的運行(即使用戶不能理解應用程序提供的語言集,也比程序崩潰要好。)

同樣,如果基於屏幕的方向,提供瞭不同的佈局資源,那麼也應該選擇一個方向作為默認佈局。例如,不要在layout-land/目錄和layout-port目錄中分別提供橫向和縱向佈局資源,而是要保留其中一個作為默認佈局,如讓layout/目錄作為默認橫行佈局資源的存放地,而layout-port/目錄保存縱向佈局資源。

提供默認資源是重要的,不僅因為可以讓應用程序在沒有預計到的設備上運行,而且還因為某些在Android新版本中添加的配置限定符,舊版本不支持。如果使用瞭新的資源限定符,但是還要維護代碼與Android舊的版本的兼容性,那麼當應用程序運行在舊的Android版本上時,如果提供默認資源,應用程序就會崩潰,因為使用瞭新的限定符命名的資源對應用程序不可用。例如,如果minSdkVersion被設置為4,並且限定瞭所有的可描畫資源都是用night模式(night和notnight限定符在API級別8以後才被添加),那麼API級別4的設備就不能訪問這些可描畫資源,應用程序就會因而崩潰。在這種情況中,可以讓notnight模式的資源作為默認資源,因此應該在可描畫資源的目錄名去除notnight限定符,使得資源目錄名如:drawable/、drawable-night/。

因此,為瞭提供最好的設備兼容性,首先應該始終提供默認資源,以便應用程序能夠獲得正確執行的資源,然後使用配置限定符給特殊的設備配置創建可選的資源。

這種規則對一種情況除外,如果應用的minSdkVersion是4或更大,在用屏幕分辨率限定符提供可選的描畫資源時,就不需要默認的可描畫資源。因為,即使沒有默認的可描畫資源,Android也能夠在可選的屏幕分辨率之間找到最匹配的資源,並且按照需要縮放位圖。但是,對於所有的設備類型,要獲取最好的體驗,應該為三種類型的分辨率提供可選的資源。如果minSdkVersion小於4(Android1.5或更低的版本),要註意屏幕的尺寸、分辨率、以及外觀限定符是不被支持的,因此對於這些版本的平臺需要執行另外的兼容性處理。

給Android1.5提供屏幕資源的兼容性

Android1.5及更低版本,不支持下列配置限定符:

分辨率:

ldpi、mdpi、hdpi、nodpi

屏幕尺寸:

small、normal、large

屏幕外觀:

long、notlong

這些配置限定符是在Android1.6中被引入的,因此Android1.5(API級別3及更低版本都不支持它們。如果使用這些配置限定符,並且沒有提供相應的默認資源,那麼Android1.5設備可能使用上述屏幕配置限定命名的任意一個資源目錄中的資源,因為它忽略這些限定符,並使用它能夠找到的第一個匹配的可描畫資源。

例如,如果應用程序支持Android1.5,並且包含瞭每種分辨率類型的可描畫資源(drawable-ldpi/、drawable-mdpi/、drawable-hdpi/),而且沒有包含默認的可描畫資源(drawable/),那麼Android1.5就會使用任意一個可描畫資源目錄中的資源,這樣就會導致用戶界面的不理想。

因此在使用屏幕配置限定符時,要提供與Android1.5及以前版本的兼容性:

1. 把中等分辨率、普通的屏幕尺寸以及非長屏幕作為默認資源來提供。

因為所有的Android1.5設備都有中等的分辨率、普通的屏幕尺寸以及非長的屏幕,所以能夠把這些類型的資源放到對應的默認資源目錄中。例如,把所有的中等分辨率的可描畫資源放到drawable/目錄中(而不是drawable-mdpi/),把normal尺寸的資源放到對應的默認資源目錄中,並且把notlong資源也放到對應的默認資源目錄中。

2. 要確保SDK工具的版本時r6或更高的版本。

SDK工具需要修訂版本6或更高,因為它包含一個新的打包工具,這個工具能夠自動的把相應版本限定符中資源應用於任何Android1.0中不存在資源目錄。例如,分辨率限定符是在Android1.6中(API級別4)被引入的,當打包工具遇到這樣的目錄時,它就會給目錄名中添加“v4”,來確保舊版本不使用這些資源(隻有API級別4和更高版本支持的限定符中的資源)。這樣,通過把中等分辨率資源放到沒有mdpi限定符的目錄中,它們依然可以被Android1.5訪問,並且支持這個分辨率限定符和有中等分辨率屏幕的任何設備也會使用這個默認資源,因為它們跟設備最匹配。

註意:Android的後續版本,如API級別8中引入的舊版本不支持的配置限定符。要提供最好的兼容性,就應該始終給每種類型的資源包含一組應用程序使用的默認資源。

Android是如何查找最佳匹配資源的

當請求一個資源時,Android會根據當前的設備配置在運行時選擇可選的資源。要演示Android是如何選擇可選資源的,先假設下列每個可描畫目錄包含瞭相同圖片的不同版本:

drawable/

drawable-en/

drawable-fr-rCA/

drawable-en-port/

drawable-en-notouch-12key/

drawable-port-ldpi/

drawable-port-notouch-12key/

並且假設設備配置如下:

地區=en-GB

屏幕方向 = port

屏幕像素分辨率=hdpi

觸屏類型=notouch

主要文本輸入方法=12key

通過比較設備配置來選擇有效的可選資源:drawable-en-port。

系統使用以下邏輯最終判斷要使用的資源:

1. 排除矛盾的設備配置的資源文件。

Drawable-fr-rCA/目錄被排除,因為它跟en-GB矛盾

drawable/

drawable-en/

drawable-fr-rCA/

drawable-en-port/

drawable-en-notouch-12key/

drawable-port-ldpi/

drawable-port-notouch-12key/

例外:屏幕像素分辨率限定符即使是矛盾的也不排除在外,即使設備的屏幕分辨率hdpi,drawable-port-ldpi/不被排除是因為在這個時點,每種分辨率都被認為是匹配的。

2. 選取列表2中最高優先級的限定符。(從MCC開始,然後向下移動)。

3. 任何的資源目錄包含這個限定符嗎?

如果沒有,則返回第2步,繼續比較下一個限定符(在這個例子中,在比較到語言限定符之前一直回到“no”)。

如果回答“yes”,那麼繼續到步驟4

4. 消除資源目錄名中不包含這個限定符的目錄,在這個例子中,系統會排除所有不包含語言限定符的目錄:

drawable/

drawable-en/

drawable-en-port/

drawable-en-notouch-12key/

drawable-port-ldpi/

drawable-port-notouch-12key/

例外:如果提問中的限定符是屏幕像素分辨率,Android會選擇那個與設備屏幕分辨率最接近的那個選項。通常,Android提供把一個大的原始圖片縮小的圖片的能力。

5. 返回,重復步驟2、3、4,直到剩下最後一個目錄。在這個例子中,屏幕方向是下一個要匹配的限定符,沒有指定屏幕方向的資源目錄就會被排除:

drawable-en/

drawable-en-port/

drawable-en-notouch-12key/

圖2.Android如何查找最佳匹配資源的流程圖

 

最後剩下的目錄是drawable-en-port

盡管每個被請求的資源都要執行這個過程,但是系統還是在某些方面做瞭一些優化。這種優化之一是一旦瞭解瞭設備配置,就可以排除不能匹配的可選資源。例如,如果配置語言是英語(“en”),那麼任何沒要設置為英語語言限定符的資源目錄就不會包含在被檢查的資源池中。

當基於屏幕尺寸限定符來選擇資源時,如果沒有更好的匹配資源,系統會使用給比當前屏幕小的屏幕設計的資源。例如,如果需要,大尺寸屏幕會使用普通尺寸屏幕的資源。但是,如果隻有比當前屏幕大的資源可用,那麼系統就不會使用它們,並且如果沒有其他的資源可用,應用程序就會崩潰。例如,如果所有的佈局資源都是針對xlarge限定符的,但是設備確實普通尺寸的屏幕,那麼應用程序就會崩潰。

註意:限定符的優先級(在表2中)比跟設備完全匹配的限定符的數量更重要。如,上述步驟4中,最後選擇的列表上包含瞭三個完全跟設備匹配的限定符(方向、觸屏類型、和輸入法),而drawable-en僅有一個參數(語言)匹配。但是由於語言的優先級比其他的限定符要高,所以drawable-port-notouche-12key就被排除瞭。

已知問題

Andrid1.5和1.6:版本限定符要完全匹配,而不是最佳匹配

正確行為是讓系統跟被標記瞭等於或小於設備平臺版本的版本限定符的資源匹配。但是在Android1.5和1.6(API級別3和4),由於有一個Bug,從而導致系統隻有在設備版本跟被標記的版本限定符完全匹配的資源才能使用。

解決方案:要遵照這種行為來提供特俗的資源。但是,因為這個Bug是固定在Android1.6以後的版本中有效,所以如果需要在Android1.5,1.6和以後的版本之間區分資源,那麼隻需要使用一個版本限定符是1.6的資源和一個跟後續所有版本都匹配的資源。這樣問題就不會有太大影響。

例如,如果要想在Android1.5、1.6和2.0.1(以及以後更新的版本)上使用不同的可描畫資源,那麼創建三個可描畫目錄:drawable/(針對1.5及更低版本)、drawable-v4(針對1.6)、;以及drawable-v6(針對2.0.1和後續版本—版本2.0,即V5不再有效)。

摘自 FireOfStar的專欄

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。