1. 程式人生 > >Android資源使用詳解

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()期間將每個資源重新分配給相應元素。