Android資源使用詳解
一、資源訪問
Android編譯時,aapt工具將生成R類,res/目錄中所有資源id都在該類中,並且每個資源型別都有相應的R子類。資源id由兩部分組成,資源型別,如string,drawable等,以及資源名稱,一般是副檔名,如果是簡單值就是android:name的屬性名稱。
訪問資源有兩種方式:
程式碼中,用R.資源型別.資源名。如,R.string.hello;
XML中,用於R類中資源id相對應的XML語法:@資源型別/資源名。如@string/hello。
注意:不要手動修改R類,因為其是由aapt工具生成,每次編譯都會被替代;為了便於本地化,應該使用字串資源。
其他方式:
1.引用樣式屬性:使用樣式屬性可在當前主題當中引用某個屬性的值。這樣不必採用硬編碼方式,而是通過為UI元素設定樣式來定製其外觀。
語法為:?[<package_name>:][<resource_type>/]<resource_name>.例如textColor="?android:textColorSecondary"其型別為attr,但是系統資源工具知道此環境中肯定含有某個屬性資源,因此無需顯示宣告。
2.訪問平臺資源:Android包含很多標準資源,如樣式、主題、佈局。要訪問這些資源,要通過android包名限定資源引用。例如將Android提供的佈局資源用於ListAdapter:
setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myarray));
二、執行時變更處理
裝置配置會在執行時發生變化(如,螢幕方向、鍵盤以及語言等)。變化時,Android會重啟執行的Activity(呼叫onDestroy()和onCreate())。目的是重新載入新裝置(配置發生變化,即視為新裝置)匹配的備用資源以適應新配置。
一般情況下,Android會在銷燬Activity之前呼叫onSaveInstanceState()方法儲存應用有關狀態。然後在onCreate()或onRestoreInstanceState()方法中恢復Activity狀態。應用應該能夠在不丟失使用者資料或狀態的情況下隨時重啟,以便使用者在配置變化或者其它原因導致的程序銷燬之後返回應用。
如果有大量資料要恢復,則成本高昂,且使用者體驗差。因此有兩個選擇:
1.在配置變更期間保留物件
允許Activity在配置變更時重啟,但是要有狀態物件傳遞給Activity的例項。
如果重啟Activity要恢復大量資料、建立網路連線或執行其他密集操作,會導致重啟緩慢,影響體驗,而通過onSaveInstanceState()回撥儲存的Bundle並不能攜帶大型資料(如點陣圖),且其中的資料要先序列化再反序列化,會消耗大量記憶體影響速度。這種情況下,如果因配置變更而重啟,則可以使用Fragment來減輕重新初始化Activity的負擔。此片段可能包含保留的有狀態物件的引用。
當Android系統因配置變更而關閉Activity時,不會銷燬已標記為要保留的Activity片段。可以將此類片段新增到Activity以保留有狀態的物件。要在執行時變更期間將有狀態的物件保留在片段中,執行以下操作:
1)繼承Fragment類並宣告對有狀態物件的引用。
2)在建立片段後呼叫setRetainInstance(true)。
3)將片段新增到Activity。
4)重啟Activity後,使用FragmentManager檢索片段。
示例:
public class RetainedFragment extends Fragment {
// 要保留的資料物件
private MyDataObject data;
//這個方法僅被呼叫一次
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 保留片段
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
注意:儘管可以儲存任何物件,但切勿傳遞與Activity繫結的物件,如Drawable、Adapter、View或其他任何與Context關聯的物件。否則,將洩漏原始Activity例項的所有檢視和資源(這裡的洩漏就是記憶體洩漏,應用將繼續持有這些資源,無法進行垃圾回收,會洩漏大量記憶體)。
再次啟動時獲得片段的應用並取得其中的資料,示例:
public class MyActivity extends Activity {
private RetainedFragment dataFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 重啟時找到保留的fragment
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// activity首次建立時,要建立fragment和資料
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}
// 後面即可通過DataFragment.getData()獲取保留的資料
...
}
@Override
public void onDestroy() {
super.onDestroy();
// 將資料保留到fragment
dataFragment.setData(collectMyLoadedData());
}
}
在onCreate()中新增一個fragment或者是恢復對其引用即可。此外,在onCreate()將狀態物件儲存在fragment內部,onDestroy()時更新可以保證內容的準確。2.自行處理配置變更
阻止系統的某些配置變更重啟Activity,在配置變化發生時接收回調,可以根據需要手動更新Activity。
但是,阻止之後系統將不會自動應用該使用的資源。只有當實在沒辦法的情況下,採用這種方法,大多數應用並不建議使用,但是其實很多新手都喜歡這樣做,本身也不會提供太多的備用資源。
在<activity>中使用android:configChanges屬性以及要處理的配置值。最常用的是orientation和keyboardHidden,分別用於避免螢幕方向和鍵盤改變導致的重啟。用|隔開。
而在Activity中會收到onConfigurationChanged()的回撥。並傳遞Configuration物件指定新裝置配置。可以通過該欄位確定配置,然後適當更改資源。呼叫此方法時,Activity的Resources物件會相應地進行更新,以根據新配置返回資源,這樣就可以在被系統不重啟Activity的情況下輕鬆重置UI元素。(這裡我想到了夜間模式的實現,算一種方法)。
注意:API13開始,裝置縱向和橫向之間切換時,螢幕尺寸也會變化。因此,如要避免其重啟,除了orientation,還有screenSize也要新增。
onConfigurationChanged()方法示例:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// 檢測螢幕方向
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
Configuration物件代表當前所有配置。很多時候並不需要知道發生哪些變化,即可以使用正確的備用資源。如,由於Resources已經更新,可以使用正確的資源。
注意:自行處理配置變更,需要為其提供備用資源的所有元素。例如,如果聲明瞭處理方向變更,則需要在onConfigurationChanged()期間將每個資源重新分配給相應元素。