Android系統設計采用代碼和布局分離的設計模式,因此在設計Android應用程序時需要遵循該設計模式。
“把非代碼資源(如圖片和字符串常量)和代碼分離開來始終是一種很好的做法。”---《Android4高級編程》
為什么要將資源和代碼進行分離?
Android支持各種資源與代碼的分離,從簡單的字符串和顏色這樣的值到更復雜的資源,例如:圖片(drawable)、動畫、主題和菜單。通過將資源分離開來,可以使它們變得更加容易維護、更新和管理。這也可以讓你通過輕松地定義多種可選的資源值來支持國際化需求,以及包含不同的資源來支持硬件的變化,特別是屏幕尺寸和分辨率的變化。當一個應用程序啟動時,不需要編寫一行代碼,Android就會自動地選擇正確的資源值。資源樹中包含對應於各種可選的硬件配置、語言和位置的值。此外,還可以根據屏幕尺寸和方向來改變布局,根據屏幕密度改變圖片,根據用戶的語言和國家定制文本提示(這些改變都是系統根據改變而自動變更的)。
如何創建分離的資源?
Android應用程序中都包含哪些可分離的資源?
所有的應用程序資源都存儲在項目層次中的res文件夾下。在這個文件夾中,每一種可用的資源類型都存儲在各自的子文件夾中。
如上圖所示,drawable-hdpi、layout、raw、values等應用程序分別包含了應用程序圖標、布局、可用資源和默認的字符串資源定義。
上述三種文件夾:drawable-hdpi、drawable-lhdpi、drawable-mhdpi、drawable-xhdpi分別對應的是不同密度的顯示屏。
每種資源類型存儲在不同的文件夾中,包括:簡單的值、Drawable、顏色、布局、動畫、樣式、菜單、XML文件(包括searchable)和原始資源。當構建應用程序的時候,這些資源會被盡可能高效地編譯和壓縮,並包含到應用程序包中。在這個過程中,還創建了R類文件,包含了對加入到項目中的每一個資源的引用。因此,可以在代碼中引用該資源。
1. 簡單的值
支持的簡單值包括字符串、顏色、尺寸、樣式和字符串數組或整型數組。所有的簡單值都存儲在res/values文件夾下的XML文件中。
每一個XML文件中,可以使用標簽來說明存儲的每一個值得類型,如:
存儲顏色的colors.xml文件,使用以下節點內容:
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="label_text">#ff2d2d2d</color> <color name="textColorPrimary">#ff2d2d2d</color>
定義顏色時,使用#符號來指定顏色值。
存儲尺寸的dimens.xml文件,使用以下節點內容:
<resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen>
可以用於創建像邊界和制圖高度這樣的布局常量。常見單位:dp非密度制約的像素(一般用於寬高),sp縮放比例無關的像素(一般用於字體大小)。允許使用相對比例來定義尺寸,以適應不同的屏幕分辨率和密度,簡化不同硬件上的縮放。
存儲字符串的strings.xml文件,使用以下節點內容:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">傳感器</string> <string name="play">播放測試音樂</string> <string name="app_name">FactoryTest</string>
字符串有助於維護應用程序內部的一致性,而且可以更容易地實現國際化。Android支持簡單的文本樣式,可以使用HTML標簽讓部分文本字符串變為粗體、斜體或帶有下划線...還可以為字符串定義復數形式,比如:
<plurals name="test_plurals"> <item quantity="one"> one music song</item> <item quantity="other"> %d music songs</item> </plurals>
存儲字符串數組的arrays.xml文件,使用以下節點內容:
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="wifi_signal"> <item>弱</item> <item>一般</item> <item>較強</item> <item>強</item> </string-array>
存儲樣式的styles.xml文件,使用以下節點內容:
<resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="TopTitleTextStyle"> <!-- Note: must be dp to fit in status bar --> <item name="android:textSize">20sp</item> <item name="android:textStyle">normal</item> </style>
樣式資源可以指定視圖所使用的屬性值,從而使應用程序保持一個一致的用戶界面體驗。主題和樣式資源最常見的用途是用來存儲應用程序的顏色和字體。
2. Drawable資源
Drawable資源包括位圖和NinePatch圖片。所有的Drawable都作為單獨的文件存儲在res/drawable文件夾下。此處支持JPG和GIF文件,但是PNG是更好的位圖格式。
3. 布局資源
布局資源可以讓你在XML文件中設計用戶界面的布局,而不是在代碼中構建它們,從而可以把表示層從業務邏輯中分離出來。布局可以用來定義任何可是組件(包括Activity、Fragment和Widget)的用戶界面。一旦在XML中進行了定義,就必須把布局填充inflate到用戶界面中。在Android中,使用布局在XML文件中創建自己的屏幕是一種最佳實踐。布局和代碼的分離可以讓你為不同的硬件配置創建優化的布局。
每一個布局定義都存儲在res/layout文件夾下的一個單獨的文件中。
4. 動畫資源
Android支持三種類型的動畫:屬性動畫;視圖動畫;幀動畫。
屬性動畫幾乎可以用來為任何東西生成動畫。每個屬性動畫都存儲在項目的res/animator文件夾下的一個單獨的XML文件中。
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="alpha" android:valueFrom="0.0" android:valueTo="1.0" />
每一個視圖動畫都存儲在項目的res/anim文件夾下的一個獨立的XML文件中。一個動畫可以定義為:alpha、scale、translate和rotate四種屬性。
<?xml version="1.0" encoding="utf-8"?> <!-- 設置動畫集合 --> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" > <rotate android:duration="1000" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:startOffset="500" android:toDegrees="360" /> <scale android:fromXScale="1.0" android:toXScale="0.0" /> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" /> <translate android:fromXDelta="0.0" android:toXDelta="1.0" /> </set>
逐幀動畫可以用來創建Drawable的序列,每個Drawable都會在視圖的背景中持續一段時間。每個Drawale存儲在res/drawable文件夾中,並使用文件名來作為資源ID。
5. 菜單
創建菜單資源並使用XML設計菜單布局,而不是在代碼中構建菜單。每個菜單定義都存儲在res/menu文件夾下的一個單獨的文件中,每個文件都只包含一個菜單。在Android中,使用XML定義慘淡是一種最佳設計實踐。
在Android應用程序中定義了相關的資源,那如何使用這些資源?
除了可以使用自定義的資源之外,Android平台提供了多個系統資源供在應用程序中使用。既可以在應用程序代碼中直接使用這些資源,也可以在其他資源中引用這些資源。
根據使用資源的不同位置,可以將方式分為以下幾種:
如何在代碼中使用資源?
可以在代碼中使用靜態R類來訪問資源。當需要一個資源本身的實例時,就需要使用輔助的方法來把它們從資源表中提取出來。在應用程序中,資源表被表示為Resource類的一個實例。這些輔助方法將在應用程序的當前資源表中執行查找,不是靜態的。
Resources res = getResources(); ObjectAnimator animator = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.anim.ani_demo); String content = res.getQuantityString(R.plurals.test_plurals, 0, 0);
Resources類為每一個可用的資源類型包含了getter,並且通常是通過傳遞的資源實例ID來起作用。
如何在資源內部引用另一個資源?
使用@符號,就可以在一個資源中引用另一個資源。
如何使用系統資源?
在代碼中使用系統資源的方法和使用自己的資源的方式相似。不同的是,要使用android.R類中使用的本地Android資源,而不是使用引用程序特定的R類。
如何在當前的主題中引用樣式?
主題是保證引用程序UI一致性的非常好的方法。Android中使用?android:而不是@來作為想要使用的資源的前綴。
<TextView android:id="@+id/tv_acc_status" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center_horizontal" android:text="Demo" android:textColor="?android:textColor" android:textSize="18sp" />
其使用方法,如上所示;但實踐中發生了崩潰。
這種技術可以創建出隨當前主題改變而改變的樣式,而不必對每一個單獨的樣式資源進行修改。
上述講述了很多關於資源的創建和使用,還有沒有其他的使用場景?
其中就有一個:為不同的語言和硬件資源創建資源。
Android系統實現了為特定的語言、位置和硬件配置創建不同的資源值,Android將會在運行時使用其動態資源選擇機制自動地從這些值中做出選擇。指定可選的資源值是通過在res文件夾下使用並行的目錄結構來實現的,並且使用連接符來分隔指定你所支持的情況的限定符。
如上所示,values-fr和values-fr-rCA代表的是法語選項和加拿大地區的法語選項。
在定制資源時有哪些可選的限定符?
1. Mobile Country Code和Mobile Network Code
2. 語言和地區
3. 屏幕像素密度,像素密度以點每英寸(dpi)來表示。分別表示ldpi、mdpi、hdpi和xhdpi來指定低120dpi、中160dpi、高240dpi和極高320dpi像素密度的資源。可以為不想縮放的位圖資源指定nodpi,以便支持精確的屏幕密度。與其他資源類型不同的是,Android在選擇資源時不要求精確匹配;當選擇合適的文件夾時,會選擇與設備的像素密度最接近的匹配,並相應地縮放產生的Drawable。
4. 屏幕大小,可選值有small、medium、large和xlarge。
對於任何資源類型,都可以指定多個限定符,並把它們用連字符隔開。任何組合都是允許的,但是它們必須按照上面列表的順序進行排列,而且每一個限定符都不能超過一個值。
當Android在運行的過程中檢索一個資源的時候,它會從可用的可選資源中選出最佳的匹配。如果在給定設備上沒有找到資源匹配,那么有用程序將會在嘗試訪問該資源時拋出一個異常。要想避免出現這種情況,應該總是在不包含限定符的文件夾中為每個資源類型包含一個默認值。
Android能夠在運行時匹配並獲取最佳資源,是否能夠更改這些資源配置?
Android支持運行時更改語言、位置和硬件,是通過終止和重啟Activity來實現上述功能的。這會強制重新評估Activity中使用的資源的分辨率,並為新的配置選擇最合適的資源值。
要想讓Activity可以監聽運行時配置更改,需要向它的manifest節點中添加一個android:configChanges屬性,並說明希望對哪些配置更改進行處理。
可監聽的設備更改有如下幾種:
1. keyboardHideen,顯示或者隱藏鍵盤或其他輸入機制;
2. orientation,屏幕在縱向和橫向之間旋轉;
等等。
可以選擇處理多個想要處理的事件,只要用管道符(|)分隔它們。
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:configChanges="orientation|screenSize" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
這個Activity會捕獲到屏幕改變的事件,添加android:configChanges屬性可以阻止由於特定配置改變而造成的重啟,而不會再次執行onCreate(),轉去執行onConfigurationChanged()。