使用資源提供最好的裝置相容性
為了讓應用程式支援多種裝置配置,始終給應用程式使用的每種資源類型都提供預設的資源是至關重要的。
例如,如果應用程式支援幾種語言,就要始終包含沒有語言和地區限定符的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中,最後選擇的列表上包含了三個完全跟裝置匹配的限定符(方向、觸屏類型、和IME),而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不再有效)。