Android SharedPreference源碼淺析

**

一、SharedPreference簡單使用

**
問題:
1.如果兩個activity都使用同一個sharedpreference,但是第一個activity沒有提交,第二個activity提交了,那麼會出現什麼結果。

2.不同的進程是否可以共享同一個sharedpreference

mode:
Context.MODE_PRIVATE:只被本地程序讀寫
Context.MODE_WORLD_READABLE:能被其他程序讀
Context:MODE_WORLD_WRITEABLE:能被其他程序讀、寫

SPActivity:

Button mButtonStorage = (Button) findViewById(R.id.btn_storage);
mButtonStorage.setOnClickListener(v -> {
SharedPreferences sp = getPreferences(MODE_PRIVATE); //這是Activity特有的方法,只是當前activity使用,其他的activity使用不了
Log.i(TAG,sp.getString("key","123"));
SharedPreferences.Editor edit = sp.edit();
edit.putString("key","key");

Log.i(TAG,sp.getString("key","123"));

Intent intent = new Intent(SPActivity.this, SPTargetActivity.class);
startActivity(intent);
});

SPTargetActivity:

Button mButtonStorage = (Button) findViewById(R.id.btn_storage);
mButtonStorage.setOnClickListener(v -> {
SharedPreferences sp = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor edit = sp.edit();
edit.putString("key","value");
edit.apply();
Log.i(TAG,sp.getString("key","123"));
});

結果
顯示從SP到SPTarget,然後返回SP過程中的結果
這裏寫圖片描述

結果說明:兩個Activity不是在同一個Sharedpreference文件進行操作

SPActivity:

Button mButtonStorage = (Button) findViewById(R.id.btn_storage);
mButtonStorage.setOnClickListener(v -> {
// SharedPreferences sp = getPreferences(MODE_PRIVATE);
SharedPreferences sp1 = getSharedPreferences("123",MODE_PRIVATE);//獲取應用目錄下的sp,應用內可以共享
Log.i(TAG,sp1.getString("key","123"));
SharedPreferences.Editor edit = sp1.edit();
edit.putString("key","key");

Log.i(TAG,sp1.getString("key","123"));

Intent intent = new Intent(SPActivity.this, SPTargetActivity.class);
startActivity(intent);
});

SPTargetActivity:

Button mButtonStorage = (Button) findViewById(R.id.btn_storage);
mButtonStorage.setOnClickListener(v -> {
// SharedPreferences sp = getPreferences("",MODE_PRIVATE);
SharedPreferences sp1 = getSharedPreferences("123",MODE_PRIVATE);

SharedPreferences.Editor edit = sp1.edit();
edit.putString("key","value");
edit.apply();
Log.i(TAG,sp1.getString("key","123"));
});

結果
顯示從SP到SPTarget,然後返回SP過程中的結果

這裏寫圖片描述

結果說明:兩個activity處理的是同一個文件,而且後一個Editor纔是有效果的,SPActivity中的Editor並沒有起作用,數據沒有提交。

**

二、源碼解析:

**

/**
  #通過 Context.getSharedPreference(),獲取對象。在所有客戶端中,Sharedpreference是單例的。
  #修改Sharedpreference必須通過提供的Editor接口,確保value值持久化存儲。
  #獲取數據通過get()方法獲取。
* #<p><em>Note: 不能用於多線程中.</em>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using SharedPreferences, read the
* <a href="{@docRoot}guide/topics/data/data-storage.html#pref">Data Storage</a>
* developer guide.</p></div>
*
* @see Context#getSharedPreferences
*/
public interface SharedPreferences {
    /**
     * Interface definition for a callback to be invoked when a shared
     * preference is changed.
        回調接口監聽器
     */
    public interface OnSharedPreferenceChangeListener {
        /**
         * Called when a shared preference is changed, added, or removed. This
         * may be called even if a preference is set to its existing value.
         *
         * <p>This callback will be run on your main thread.
         *
         * @param sharedPreferences The {@link SharedPreferences} that received
         *            the change.
         * @param key The key of the preference that was changed, added, or
         *            removed.
         */
        void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
    }

    /**
     #用於修改Sharedpreference中的值。但是所有的修改的值,必須在調用方法commit 或者 apply方法之後才能成功修改
     */
    public interface Editor {
        /**
         * Set a String value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         *
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.  Passing {@code null}
         *    for this argument is equivalent to calling {@link #remove(String)} with
         *    this key.
         *
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putString(String key, @Nullable String value);

        /**
         * Set a set of String values in the preferences editor, to be written
         * back once {@link #commit} or {@link #apply} is called.
         *
         * @param key The name of the preference to modify.
         * @param values The set of new values for the preference.  Passing {@code null}
         *    for this argument is equivalent to calling {@link #remove(String)} with
         *    this key.
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putStringSet(String key, @Nullable Set<String> values);

        /**
         * Set an int value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         *
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         *
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putInt(String key, int value);

        /**
         * Set a long value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         *
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         *
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putLong(String key, long value);

        /**
         * Set a float value in the preferences editor, to be written back once
         * {@link #commit} or {@link #apply} are called.
         *
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         *
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putFloat(String key, float value);

        /**
         * Set a boolean value in the preferences editor, to be written back
         * once {@link #commit} or {@link #apply} are called.
         *
         * @param key The name of the preference to modify.
         * @param value The new value for the preference.
         *
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor putBoolean(String key, boolean value);

        /**
         * Mark in the editor that a preference value should be removed, which
         * will be done in the actual preferences once {@link #commit} is
         * called.
         #標記key對應的記錄應該被刪除,但是必須在commit執行之後才能刪除數據
         *
         * <p>Note that when committing back to the preferences, all removals
         * are done first, regardless of whether you called remove before
         * or after put methods on this editor.
         #當執行commit方法,提交的時候,所有之前標記刪除的操作都會先執行,無論是在put存數據之前還是之後是否執行了。也就是說,刪除操作都會先執行,和刪除的代碼在哪裏沒關係。
         *
         * @param key The name of the preference to remove.
         *
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor remove(String key);

        /**
         * Mark in the editor to remove <em>all</em> values from the
         * preferences.  Once commit is called, the only remaining preferences
         * will be any that you have defined in this editor.
         #在editor標記中,刪除所有數據。一旦提交,剩下的首選項將是您在這個編輯器中定義的任何參數
         *
         * <p>Note that when committing back to the preferences, the clear
         * is done first, regardless of whether you called clear before
         * or after put methods on this editor.
       #和刪除操作一樣,清空操作都會先執行
         *
         * @return Returns a reference to the same Editor object, so you can
         * chain put calls together.
         */
        Editor clear();

        /**
         * 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.
         #從Editor中提交變化到正在修改的Sharedpreference中。這是自動執行的修改,無論是否在當前的Sharedpreference中,都會進行替換
         *
         * <p>Note that when two editors are modifying preferences at the same
         * time, the last one to call commit wins.
         #當兩個Editor同時修改preference的時候,後一個執行的纔有效
         *
         * <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.
         #如果不關心返回值,而且是在主線程中操作的,可以考慮使用apply方法
         *
         * @return Returns true if the new values were successfully written
         * to persistent storage.
         */
        boolean 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.
        # 從Editor中提交變化到正在修改的Sharedpreference中。這是自動執行的修改,無論是否在當前的Sharedpreference中,都會進行替換
         *
         * <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.
         #不像commit方法,它同步的寫preferences到持久化存儲。apply提交變化值到內存中,Sharedpreference立即開啓一個異步提交到磁盤中,而且你不會收到任何失敗的信息。如果同時另一個editor調用commit方法,這是將會先執行apply方法,commit()將會被阻塞,知道所有的異步提交完成,以及提交自身。
         *
         * <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.
         #在一個進程中,Sharedpreference是單例的,如果你已經不關注返回值了,使用apply替換commit就是安全的
         *
         * <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.
         #你不需要擔心android組件風格和他們的相互作用,當使用apply寫到磁盤存儲的時候。框架確保在轉變狀態之前,運轉的磁盤能夠從apply()方法完成寫操作。
         *
         * <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>.
         #SharedPreferences.Editor接口是不希望直接實現的。然而,如果你之前已經實現了,並且現在正在獲取有關缺少apply()方法的錯誤,則你只需要從apply()調用commit即可。
         */
        void apply();
    }

    /**
     * Retrieve all values from the preferences.
      #從preference中取回所有鍵值對
     * <p>Note that you <em>must not</em> modify the collection returned
     * by this method, or alter any of its contents.  The consistency of your
     * stored data is not guaranteed if you do.
     #禁止改變返回的集合,或者修改內容。如果你做了,保存數據的一致性也不會被保證。
     *
     * @return Returns a map containing a list of pairs key/value representing
     * the preferences.
     *
     * @throws NullPointerException
     */
    Map<String, ?> getAll();

    /**
     * Retrieve a String value from the preferences.
     #根據key獲取對應的String類型的value值
     * @param key The name of the preference to retrieve.
     * @param defValue Value to return if this preference does not exist.
     *
     * @return Returns the preference value if it exists, or defValue.  Throws
     * ClassCastException if there is a preference with this name that is not
     * a String.
     *
     * @throws ClassCastException
     */
    @Nullable
    String getString(String key, @Nullable String defValue);

    /**
     * Retrieve a set of String values from the preferences.
     #從preference中取回String類型值的集合
     * <p>Note that you <em>must not</em> modify the set instance returned
     * by this call.  The consistency of the stored data is not guaranteed
     * if you do, nor is your ability to modify the instance at all.
     *
     * @param key The name of the preference to retrieve.
     * @param defValues Values to return if this preference does not exist.
     *
     * @return Returns the preference values if they exist, or defValues.
     * Throws ClassCastException if there is a preference with this name
     * that is not a Set.
     *
     * @throws ClassCastException
     */
    @Nullable
    Set<String> getStringSet(String key, @Nullable Set<String> defValues);

    /**
     * Retrieve an int value from the preferences.
     *
     * @param key The name of the preference to retrieve.
     * @param defValue Value to return if this preference does not exist.
     *
     * @return Returns the preference value if it exists, or defValue.  Throws
     * ClassCastException if there is a preference with this name that is not
     * an int.
     *
     * @throws ClassCastException
     */
    int getInt(String key, int defValue);

    /**
     * Retrieve a long value from the preferences.
     *
     * @param key The name of the preference to retrieve.
     * @param defValue Value to return if this preference does not exist.
     *
     * @return Returns the preference value if it exists, or defValue.  Throws
     * ClassCastException if there is a preference with this name that is not
     * a long.
     *
     * @throws ClassCastException
     */
    long getLong(String key, long defValue);

    /**
     * Retrieve a float value from the preferences.
     *
     * @param key The name of the preference to retrieve.
     * @param defValue Value to return if this preference does not exist.
     *
     * @return Returns the preference value if it exists, or defValue.  Throws
     * ClassCastException if there is a preference with this name that is not
     * a float.
     *
     * @throws ClassCastException
     */
    float getFloat(String key, float defValue);

    /**
     * Retrieve a boolean value from the preferences.
     *
     * @param key The name of the preference to retrieve.
     * @param defValue Value to return if this preference does not exist.
     *
     * @return Returns the preference value if it exists, or defValue.  Throws
     * ClassCastException if there is a preference with this name that is not
     * a boolean.
     *
     * @throws ClassCastException
     */
    boolean getBoolean(String key, boolean defValue);

    /**
     * Checks whether the preferences contains a preference.
     #判斷是否包含key
     * @param key The name of the preference to check.
     * @return Returns true if the preference exists in the preferences,
     *         otherwise false.
     */
    boolean contains(String key);

    /**
     * Create a new Editor for these preferences, through which you can make
     * modifications to the data in the preferences and atomically commit those
     * changes back to the SharedPreferences object.
     *
     * <p>Note that you <em>must</em> call {@link Editor#commit} to have any
     * changes you perform in the Editor actually show up in the
     * SharedPreferences.
     *
     * @return Returns a new instance of the {@link Editor} interface, allowing
     * you to modify the values in this SharedPreferences object.
     */
    Editor edit();

    /**
     * Registers a callback to be invoked when a change happens to a preference.
     #註冊一個回調函數,當preference被改變的時候,能夠被調用
     * <p class="caution"><strong>Caution:</strong> The preference manager does
     * not currently store a strong reference to the listener. You must store a
     * strong reference to the listener, or it will be susceptible to garbage
     * collection. We recommend you keep a reference to the listener in the
     * instance data of an object that will exist as long as you need the
     * listener.</p>
     *
     * @param listener The callback that will run.
     * @see #unregisterOnSharedPreferenceChangeListener
     */
    void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);

    /**
     * Unregisters a previous callback.
     #取消註冊之前的回調函數
     * @param listener The callback that should be unregistered.
     * @see #registerOnSharedPreferenceChangeListener
     */
    void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
}

Context.java中調用Sharedpreference方法的方法:

/**
* Retrieve and hold the contents of the preferences file 'name', returning
* a SharedPreferences through which you can retrieve and modify its
* values.  Only one instance of the SharedPreferences object is returned
* to any callers for the same name, meaning they will see each other's
* edits as soon as they are made.
#取回並且持有文件名爲name的preferences內容,返回Sharedpreference,然後你可以取回和修改內容。Sharedpreference僅有一個實例能夠被返回給任何調用者。意味着,一旦某個使用者作出改變,其他人都能看見他的編輯。

* @param name Desired preferences file. If a preferences file by this name
* does not exist, it will be created when you retrieve an
* editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
* @param mode Operating mode.
*
* @return The single {@link SharedPreferences} instance that can be used
*         to retrieve and modify the preference values.
*
* @see #MODE_PRIVATE
*/
public abstract SharedPreferences getSharedPreferences(String name, @PreferencesMode int mode);

/**
* Retrieve and hold the contents of the preferences file, returning
* a SharedPreferences through which you can retrieve and modify its
* values.  Only one instance of the SharedPreferences object is returned
* to any callers for the same name, meaning they will see each other's
* edits as soon as they are made.
*
* @param file Desired preferences file. If a preferences file by this name
* does not exist, it will be created when you retrieve an
* editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
* @param mode Operating mode.
*
* @return The single {@link SharedPreferences} instance that can be used
*         to retrieve and modify the preference values.
*
* @see #getSharedPreferencesPath(String)
* @see #MODE_PRIVATE
* @removed
*/
public abstract SharedPreferences getSharedPreferences(File file, @PreferencesMode int mode);

/**
* Move an existing shared preferences file from the given source storage
* context to this context. This is typically used to migrate data between
* storage locations after an upgrade, such as moving to device protected
* storage.
*
* @param sourceContext The source context which contains the existing
*            shared preferences to move.
* @param name The name of the shared preferences file.
* @return {@code true} if the move was successful or if the shared
*         preferences didn't exist in the source context, otherwise
*         {@code false}.
* @see #createDeviceProtectedStorageContext()
*/
public abstract boolean moveSharedPreferencesFrom(Context sourceContext, String name);

/**
* Delete an existing shared preferences file.
*
* @param name The name (unique in the application package) of the shared
*            preferences file.
* @return {@code true} if the shared preferences file was successfully
*         deleted; else {@code false}.
* @see #getSharedPreferences(String, int)
*/
public abstract boolean deleteSharedPreferences(String name);

/**
* Returns the absolute path on the filesystem where a file created with
* {@link #getSharedPreferences(String, int)} is stored.
* <p>
* The returned path may change over time if the calling app is moved to an
* adopted storage device, so only relative paths should be persisted.
*
* @param name The name of the shared preferences for which you would like
*            to get a path.
* @return An absolute path to the given file.
* @see #getSharedPreferences(String, int)
* @removed
*/
public abstract File getSharedPreferencesPath(String name);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章