2014年7月28日 星期一

使用 SharedPreferences 來儲存名稱與值 (key/value) 的對應資料


在開發程式時如果有需要儲存一些名稱 (key) 與值 (value) 的對應資料 (只限基本型態的資料,如:int, float, boolean, long 等),可透過 SharedPreferences 物件來達成。例如使用者在成功登入 App 之後將帳號記錄下來,在下次登入時自動帶出,此時使用者就只需要輸入密碼即可。

infor from: http://android-deve.blogspot.tw/2012/11/sharedpreferences-keyvalue.html

A. 使用的物件以及方法

  1. Context
    • SharedPreferences getSharedPreference(String name, int mode)
  2. Activity
    • SharedPreferences getPreferences(int mode)
  3. SharedPreferences
    • public abstract boolean contains(String key)
    • public abstract SharedPreferences.Editor edit()
    • public abstract Map<String, ?> getAll()
    • public abstract boolean getBoolean(String key, boolean defValue)
    • public abstract float getFloat(String key, float defValue)
    • public abstract int getInt(String key, int defValue)
    • public abstract long getLong(String key, long defValue)
    • public abstract String getString(String key, String defValue)
    • public abstract Set<String> getStringSet(String key, Set<String> defValues)
  4. SharedPreferences.Editor
    • public abstract void apply()
    • public abstract Editor clear()
    • public abstract boolean commit()
    • public abstract Editor putBoolean(String key, boolean value)
    • public abstract Editor putFloat(String key, float value)
    • public abstract Editor putInt(String key, int value)
    • public abstract Editor putLong(String key, long value)
    • public abstract Editor putString(String key, String value)
    • public abstract Editor putStringSet(String key, Set<String> values)
    • public abstract Editor remove(String key)

B. 原理說明

  1. 在 Android 平台上一個 SharedPreferences 物件會對應到一個檔案,這個檔案中儲存 key/value 的對應資料,而SharedPreferences 物件提供了一些對應的方法來讀寫這些資料。

  2. 每一個儲存 key/value 的 SharedPreferences 檔案都是由 Android 平台管理,在取得 SharedPreferences 物件時系統會自動建立 SharedPreference 檔案 (如果檔案不存在就會建立一個新的),可透過參數設定該檔案的權限只有目前 App 可以存取,或開放給其他 App 讀取或寫入 (當然,其他 App 要知道這個檔案的擺放位置才行)。

  3. 使用 Context.getSharedPreference(String name, int mode) 方法可以建立多個 SharedPreferences 檔案,每一個檔案透過 name 參數來命名,該檔案的讀寫權限則是利用 mode 參數來做設定。

  4. Context.getSharedPreference() 方法執行後,系統就會在 /data/data/[package.name]/shared_prefs/ 目錄底下建立一個 name.xml 的檔案 (name 就是該方法傳入的參數),並依據 mode 參數來設定檔案的讀寫權限。舉例來說,在 com.myapp.MyActivity 中呼叫 getApplication().getSharedPreferences("ap_setting", Context.MODE_PRIVATE); 之後,就會在 /data/data/com.myapp/ 目錄下產生一個 ap_setting.xml 檔案。

  5. 使用 Activity.getPreferences(int mode) 可以建立一個讓目前的 Activity 使用的 SharedPreferences 檔案 (其他的 Activity 無法使用)。事實上 getPreferences(int mode) 底層也是呼叫 Context.getSharedPreference(String name, int mode) 方法,並將目前 Activity 的名稱當作 name 參數傳入。因此,這個方法執行後會在 /data/data/[package.name]/shared_prefs/ 目錄底下會產生一個以 Activity 名稱為檔名的 XML 檔,如:MyActivity.xml。

  6. 在呼叫 Context.getSharedPreference() 或 Activity.getPreferences() 來取得 SharedPreferences 物件時,系統會檢查對應的 SharedPreferences 檔案是否存在,如果存在就將 SharedPreferences 物件指向該檔案,若不存在則會建立一個新的檔案,並將物件指向該檔案。

  7. getPreferences() 方法中的 mode 參數可以是以下三種:
    • MODE_PRIVATE: 建立的 SharedPreferences 檔案只能讓目前的 App 讀寫
    • MODE_WORLD_READABLE: 除了目前 App 可以讀寫外,也能讓其他的 App 讀取,當然其他 App 要知道該檔案的擺放位置
    • MODE_WORLD_WRITEABLE: 除了目前 App 可以讀寫外,也能讓其他的 App 寫入,當然其他 App 要知道該檔案的擺放位置

  8. 要修改 SharedPreferences 裡面的資料 (將資料存入或刪除) 必須透過 SharedPreferences.Editor 物件來達成,當SharedPreferences 裡面的資料被修改後,必須呼叫 commit() 或 apply() 讓修改結果生效。commit() 與 apply() 的差別在於 commit() 會直接將異動結果寫入檔案,apply() 則是修改記憶體中的暫存資料,並以非同步方式將結果寫入檔案中。

    C. 使用方式

    1. 取得 SharedPreferences 物件讓目前的 Activity 使用

    //取得一個 SharedPreferences 物件讓目前的 Activity 使用,
    //產生的 SharedPreferences 檔案「無法讓其他 App 存取」
    SharedPreferences spref = getPreferences(MODE_PRIVATE);
    ...
    //取得一個 SharedPreferences 物件讓目前的 Activity 使用,
    //產生SharedPreferences 檔案「可以讓其他 App 讀取」
    SharedPreferences spref = getPreferences(MODE_WORLD_READABLE);
    ...
    //取得一個 SharedPreferences 物件讓目前的 Activity 使用,
    //產生SharedPreferences 檔案「可以讓其他 App 寫入」
    SharedPreferences spref = getPreferences(MODE_WORLD_WRITEABLE);
    ...
    2. 取得 SharedPreferences 物件讓多個 Activity 使用

    //KEY 值可以任意給定,只要用同一個 KEY 就可以存取同一個 SharedPreferences 檔案
    public static final String KEY = "com.my.package.app";
    ...
    //取得一個 SharedPreferences 物件讓同一個 App 裡面的不同 Activity 可以共同使用
    SharedPreferences spref = getApplication().
                              getSharedPreference(KEY, Context.MODE_PRIVATE);
    
    3. 將資料存入 SharedPreferences

    //由 SharedPreferences 中取出 Editor 物件,透過 Editor 物件將資料存入
    SharedPreferences.Editor editor = spref.edit();
    
    //清除 SharedPreferences 檔案中所有資料
    editor.clear();
    
    //儲存 boolean 型態的資料
    editor.putBoolean("KEY_BOOL", true);
    
    //儲存 float 型態的資料
    editor.putFloat("KEY_FLOAT", 18);
    
    //將目前對 SharedPreferences 的異動寫入檔案中
    //如果沒有呼叫 apply(),則異動的資料不會生效
    editor.apply();
    
    //儲存 long 型態的資料
    editor.putLong("KEY_LONG", 100);
    
    //儲存字串型態的資料
    editor.putString("KEY_STRING", "Android 開發");
    
    //儲存集合型態的資料
    HashSet<String> hs = new HashSet<String>();
    hs.add("一月"); hs.add("二月");
    editor.putStringSet("KEY_STR_SET", hs);
    
    //移除 KEY_STRING 對應的資料
    editor.remove("KEY_STRING");
    
    //將目前對 SharedPreferences 的異動寫入檔案中
    //如果沒有呼叫 commit(),則異動的資料不會生效
    editor.commit();
    
    4. 取出 SharedPreferences 裡面的資料

    //取出 SharedPreferences 物件,若 SharedPreference 檔案不存在就會建立一個新的
    SharedPreferences spref = getPreferences(MODE_PRIVATE);
    
    //透過 KEY_BOOL key 取出 boolean 型態的資料,若資料不存在則回傳 true
    boolean booValue = spref.getBoolean("KEY_BOOL", true);
    
    //透過 KEY_FLOAT key 取出 float 型態的資料,若資料不存在則回傳 0
    float floatValue = spref.getFloat("KEY_FLOAT", 0);
    
    //透過 KEY_LONG key 取出 long 型態的資料,若資料不存在則回傳 0
    long longValue = spref.getLong("KEY_LONG", 0);
    
    //透過 KEY_STRING key 取出字串型態的資料,若資料不存在則回傳 null
    String strValue = spref.getString("KEY_STRING", null);
    
    //透過 KEY_STR_SET key 取出集合型態的資料,若資料不存在則回傳 null
    HashSet<String> hs = (HashSet<String>) spref.getStringSet("KEY_STR_SET", null);
    
    //回傳 KEY_STRING 是否在在 SharedPreferences 檔案中
    boolean exists = spref.contains("KEY_STRING")


    D. 完整實例

    package com.test;
    
    import java.util.HashSet;
    import android.app.Activity;
    import android.content.SharedPreferences;
    import android.os.Bundle;
    
    public class MyActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            SharedPreferences spref = getPreferences(MODE_PRIVATE);
            SharedPreferences.Editor editor = spref.edit();
            editor.clear();
    
            editor.putBoolean("KEY_BOOL", true);
            editor.putFloat("KEY_FLOAT", 18);  
            editor.apply();
    
            editor.putLong("KEY_LONG", 100);
            editor.putString("KEY_STRING", "Android 開發");
    
            HashSet<String> hs = new HashSet<String>();
            hs.add("一月");
            hs.add("二月");
            editor.putStringSet("KEY_STR_SET", hs);
    
            editor.remove("KEY_STRING");
            editor.commit();
        }
    }
    當 MyActivity 的 onCreate() 執行完畢後,就會在 /data/data/com.test/shared_prefs/ 目錄下產生一個 MyActivity.xml 檔案,檔案內容如下所示:
    <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    <map>
      <boolean name="KEY_BOOL" value="true" />
      <long name="KEY_LONG" value="100" />
      <float name="KEY_FLOAT" value="18.0" />
      <set name="KEY_STR_SET">
        <string>一月</string>
        <string>二月</string>
      </set>
    </map>

    沒有留言:

    張貼留言