1. 程式人生 > >Android資料儲存之SharedPreferences詳細總結

Android資料儲存之SharedPreferences詳細總結

Android中常見的幾種儲存方式:

  1. SharedPreferences
  2. SQLite資料庫儲存
  3. 檔案儲存
  4. 網路儲存

其中也許最常用的就是SharedPreferences儲存和檔案儲存了,今天總結一下SharedPreferences。帶著問題學習SharedPreferences:
問題:

  • 儲存的位置是在哪
  • SharedPreferences儲存的檔案格式是什麼
  • 如何檢視
  • 建立的時候需要context,不同的context建立有沒有區別
  • 建立的幾種mode以及區別
  • apply和commit的區別
  • 存取資料使用多張表還是一張表

看完下面的講解,你應該就能回答上面的問題了

google官方說明

SharedPreferences 類提供了一個通用框架,以便您能夠儲存和檢索原始資料型別的永久性鍵值對。 您可以使用 SharedPreferences 來儲存任何原始資料:布林值、浮點值、整型值、長整型和字串。 此資料將跨多個使用者會話永久保留(即使您的應用已終止亦如此)。

要獲取應用的 SharedPreferences 物件,請使用以下兩個方法之一:

  • getSharedPreferences() - 如果您需要多個按名稱(使用第一個引數指定)識別的首選項檔案,請使用此方法。
  • getPreferences() - 如果您只需要一個用於 Activity 的首選項檔案,請使用此方法。 由於這將是用於 Activity 的唯一首選項檔案,因此無需提供名稱。

我先在Activity A中寫入

SharedPreferences settings = getSharedPreferences("test", 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("num", 23);
System.out.println("-----------寫入");

列印:
I/System.out: ———–寫入

然後在Activity B中檢視

SharedPreferences settings = getSharedPreferences("test", 0);
int num = settings.getInt("num", 0);
System.out.println("-----------num="+num);

列印:
I/System.out: ———–num=23

儲存的位置是在哪

如果你使用的是3.0以前的Android studio版本,可以在通過DDMS的【File Explorer】中檢視,如果你使用的是3.0以及以後的Android studio版本,可以直接通過一下步驟開啟

點選 View > Tool Windows > Device File Explorer 或工具視窗欄中的 Device File Explorer 按鈕以開啟裝置檔案瀏覽器。

注意需要用模擬器檢視,手機沒有root是看不到的

這裡寫圖片描述

找到data\data\程式包名\shared_prefs目錄,你會發現你剛建立的檔案
這裡寫圖片描述

SharedPreferences儲存的檔案格式是什麼

這裡寫圖片描述
我想你應該也看到了是xml檔案
內容是:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <int name="num" value="23" />
</map>

如何檢視

如果是開發上面就是檢視過程,如果是真機需要把手機root,才有許可權檢視

建立的時候需要context,不同的context建立有沒有區別

我是在不同的Activity中寫入和檢視的,但是操作的是同一個test.xml,所以不同的Context操作只要getSharedPreferences(“test”, 0);獲取SharedPreferences時傳入的第一個引數name相同就得到是相同的SharedPreferences,操作的是同一個xml檔案。

那麼如何獲取一個Activity單獨的SharedPreferences呢?Google已經說了

getPreferences() - 如果您只需要一個用於 Activity 的首選項檔案,請使用此方法。 由於這將是用於 Activity 的唯一首選項檔案,因此無需提供名稱

可以檢視原始碼,其實就是獲取了當前Activity的ClassName,所以這個name是單獨的,所以產生的也是用於 此Activity 的唯一首選項檔案

/**
     * Retrieve a {@link SharedPreferences} object for accessing preferences
     * that are private to this activity.  This simply calls the underlying
     * {@link #getSharedPreferences(String, int)} method by passing in this activity's
     * class name as the preferences name.
     *
     * @param mode Operating mode.  Use {@link #MODE_PRIVATE} for the default
     *             operation.
     *
     * @return Returns the single SharedPreferences instance that can be used
     *         to retrieve and modify the preference values.
     */
    public SharedPreferences getPreferences(@Context.PreferencesMode int mode) {
        return getSharedPreferences(getLocalClassName(), mode);
    }

建立時的幾種mode以及區別

上面獲取SharedPreferences的時候我直接使用的是getSharedPreferences(“test”, 0),第二個引數傳入的是0,代表操作模式是MODE_PRIVATE
操作模式有以下幾種:

  1. MODE_PRIVATE
  2. MODE_WORLD_READABLE
  3. MODE_WORLD_WRITEABLE
  4. MODE_APPEND
  5. MODE_MULTI_PROCESS

Context.MODE_PRIVATE:為預設操作模式,代表該檔案是私有資料,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原檔案的內容
Context.MODE_APPEND:模式會檢查檔案是否存在,存在就往檔案追加內容, 而不是擦除以前的,否則就建立新檔案。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用來控制其他應用是否有許可權讀寫該檔案。
MODE_WORLD_READABLE:表示當前檔案可以被其他應用讀取。
MODE_WORLD_WRITEABLE:表示當前檔案可以被其他應用寫入。

以上是我看的網上的說法,但是我在最新的Android Studio上開發,也就是在Android Studio3.1上去看到了下面的場景:
這裡寫圖片描述

MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE和MODE_MULTI_PROCESS都被廢棄了

然後我又試了下MODE_APPEND,又給了我以下的提示:
Must be one or more of: Context.MODE_PRIVATE, Context.MODE_WORLD_READABLE, Context.MODE_WORLD_WRITEABLE, Context.MODE_MULTI_PROCESS less… (⌘F1)

看來目前能用的只能是MODE_PRIVATE了,其他的不用考慮了

apply和commit的區別

先看看兩者的說明:

/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing.  This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call commit wins.
*
* <p>If you don't care about the return value and you're
* using this from your application's main thread, consider
* using {@link #apply} instead.
*
* @return Returns true if the new values were successfully written
* to persistent storage.
*/
boolean commit();

1,commit方法是有一個boolean的返回值
2,當資料變化進行儲存時是一個原子性的操作
3,當兩個editor物件同時對一個共享的preferences引數進行操作時,永遠都是最後一個呼叫commit方法的editor變更了最後的資料值


/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing.  This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call apply wins.
*
* <p>Unlike {@link #commit}, which writes its preferences out
* to persistent storage synchronously, {@link #apply}
* commits its changes to the in-memory
* {@link SharedPreferences} immediately but starts an
* asynchronous commit to disk and you won't be notified of
* any failures.  If another editor on this
* {@link SharedPreferences} does a regular {@link #commit}
* while a {@link #apply} is still outstanding, the
* {@link #commit} will block until all async commits are
* completed as well as the commit itself.
*
* <p>As {@link SharedPreferences} instances are singletons within
* a process, it's safe to replace any instance of {@link #commit} with
* {@link #apply} if you were already ignoring the return value.
*
* <p>You don't need to worry about Android component
* lifecycles and their interaction with <code>apply()</code>
* writing to disk.  The framework makes sure in-flight disk
* writes from <code>apply()</code> complete before switching
* states.
*
* <p class='note'>The SharedPreferences.Editor interface
* isn't expected to be implemented directly.  However, if you
* previously did implement it and are now getting errors
* about missing <code>apply()</code>, you can simply call
* {@link #commit} from <code>apply()</code>.
*/
void apply();

1,apply方法是沒有返回值的
2,當兩個editor同時對preferences物件編輯時,也是最後一個呼叫apply方法的物件編輯資料
3,apply的提交操作也是原子性的

其實我們Android studio的很強大,當你使用editor.commit();的時候直接推薦你使用apply,commit直接寫入持久化記憶體,apply在後臺處理它

Consider using apply() instead; commit writes its data to persistent storage immediately, whereas apply will handle it in the background

他們的區別總結:
apply()沒有返回值,commit()有返回值,在不關心結果的時候推薦使用apply()
commit()直接寫入持久化記憶體,是同步過程,速度比apply()慢,apply()是非同步的提交,速度更快

存取資料使用多張表還是一張表

我們知道SharedPreferences儲存的格式是xml,既然是xml就要用到解析,只不過這個解析過程我們是看不到的也不需要去關心,但是解析的速度卻會影響到我們的使用者體驗,加入一張表裡面有很多資料,比如你把一個頁面的資料存起來了,資料量比較大,那麼這個時候推薦為這些資料單獨建立一個表,也就是推薦不同的資料放不同的表裡面,防止所有資料都放在一張表裡面一次讀取要耗費很長時間