??SharedPreference性能優(yōu)化看這一篇就夠了

image

性能優(yōu)化是一條漫長的路席揽,走著走著就迷了路,一直走,一直迷...

小小簡介

SharedPreference是Android系統(tǒng)中一種簡單的、輕量級的文件存儲窥摄,它是一種持久化的存儲方式抑片,以名稱/值對(NVP)機制存放在xml中map根標(biāo)簽下,正如其名无虚,它比較適合一些簡單數(shù)據(jù)的存儲,用于保存Int、long聂宾、boolean、String诊笤、Float系谐、Set這些數(shù)據(jù)類型,可以在data/data/應(yīng)用程序/shared_prefs的目錄下可以查找到保存的xml文件讨跟。

基本使用方式

  • 獲取SharedPreference對象
SharedPreferences sp = context.getSharedPreferences(PREFERENCES_NAME,Context.MODE_PRIVATE);
  • 獲取 SharedPreferences.Editor
SharedPreferences.Editor edit = sp.edit();
  • 存儲數(shù)據(jù)
edit.putString(String key,String value);
edit.putStringSet(String key, Set<String> values);
edit.putLong(String key,long value);
edit.putFloat(String key,float value);
edit.putBoolean(String key,boolean value);
edit.putInt(String key,int value);
edit.commit();//同步寫入纪他,頻繁讀取會阻塞主線程,引起ANR
edit.apply();//異步寫入晾匠,不關(guān)心結(jié)果茶袒,官方推薦,速度與性能較好
  • 獲取數(shù)據(jù)
sp.getString(String key,String value);
sp.getStringSet(String key, Set<String> values);
sp.getLong(String key,long value);
sp.getFloat(String key,float value);
sp.getBoolean(String key,boolean value);
sp.getInt(String key,int value);

這些基本使用方式應(yīng)該不用啰嗦去介紹了凉馆,本文主要談一些SP存儲上的優(yōu)化建議??薪寓,下圖為自己在SP讀寫性能上的測試乾巧,僅供參考:

耗時統(tǒng)計

存儲方式 數(shù)據(jù)條數(shù) 耗時/ms
多次commit 1000 15052
一次性commit 1000 24
多次apply 1000 588
一次性apply 1000 12
json 1000 73

從耗時統(tǒng)計上看,在操作上预愤,明顯能看出頻繁執(zhí)行commit與apply操作是非常耗時的沟于,那么卡頓的解決方案也呼之而出;在使用上植康,使用commit與apply的區(qū)別旷太,雖然都是保存數(shù)據(jù),但是在性能和耗時上也略顯不同销睁;在數(shù)據(jù)格式上供璧,json文件與簡單的KV數(shù)據(jù)性能上的差別。下面是結(jié)合這個測試結(jié)果給出的一些建議:

關(guān)于優(yōu)化的建議

  • 建議在Application中初始化冻记,重寫attachBaseContext()睡毒,參數(shù)context直接傳入Application對象即可。
  • 最好使用單例冗栗,不必每次都從系統(tǒng)獲取Sp對象演顾,減少開銷。
  • 如果項目中使用了MultiDex隅居,存在分包钠至,請在分包前即MultiDex.install()之前或者在multidex執(zhí)行的這段時間初始化。因為這時cpu是利用不滿的胎源,我們沒有辦法充分利用CPU的原因棉钧,是因為如果我們在Multidex之前執(zhí)行一些操作,我們很有可能因為這樣一些操作的類或者是相關(guān)的類不在我們的主dex當(dāng)中涕蚤,在四點幾版本中會直接崩潰宪卿,但是由于sharePreference不會產(chǎn)生這種崩潰,它是系統(tǒng)的類万栅。
  • 請不要使用SharedPreference存儲大文件及存儲大量的key和value佑钾,這樣的話會造成界面卡頓或者ANR比較占內(nèi)存,記住它是簡單存儲申钩,如果有類似的需求請考慮數(shù)據(jù)庫次绘、磁盤文件存儲等等瘪阁。
  • 推薦使用apply進(jìn)行存儲撒遣,這也是官方推薦,當(dāng)讀入內(nèi)存后管跺,因為它是異步寫入磁盤的义黎,所以效率上會比commit好,如果你需要存儲狀態(tài)或者即存即用的話還是盡量使用commit豁跑。
  • 請不要頻繁使用apply與commit廉涕,如果存在這樣的問題,請合并一次性apply與commit,可以參考封裝一個map的結(jié)合,一次性提交狐蜕,因為SharedPreference可能會存在IO瓶頸和鎖性能差的問題宠纯。
  • 盡量不要存放Json及html,數(shù)據(jù)少可以层释,無需擔(dān)心婆瓜,大量的話請放棄。
  • 不要所有的數(shù)據(jù)都存在一個文件贡羔,不同類型的文件或者數(shù)據(jù)可以分開多個文件存儲廉白,避免使用一個大文件,這樣可提高讀取速度乖寒。
  • 跨進(jìn)程操作不要使用MULTI_PROCESS標(biāo)志猴蹂,而是使用contentprovide等進(jìn)程間通信的方式。
  • 如果你的項目對于存儲性能要求非常高的情況楣嘁,可以考慮放棄系統(tǒng)的SP存儲磅轻,推薦你使用騰訊的高性能組件MMKV,目前超過8.8k+的star逐虚。
    image

SP工具類

封裝是基于AndroidUtilCode進(jìn)行的部分改造瓢省,增加了提交Map的操作,方便一次性commit與apply痊班,操作時請直接使用SpHelpUtils輔助類勤婚,需要的話直接復(fù)制+粘貼,減少跳轉(zhuǎn)GitHub的時間涤伐,程序員就應(yīng)該懶到極致馒胆。

/**
 * description:SpUtils工具類的封裝類(使用前,請在相應(yīng)app的Applicaiton中初始化凝果,傳入getApplicationContext())
 */
public class SpHelpUtils {
    /**
     * 簡單存儲工具類
     */
    private static SpUtils sDefaultSpUtils;

    /**
     * Set the default instance of {@link SpUtils}.
     *
     * @param spUtils The default instance of {@link SpUtils}.
     */
    public static void setDefaultSpUtils(final SpUtils spUtils) {
        sDefaultSpUtils = spUtils;
    }

    /**
     * Put the string value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public static void put(@NonNull final String key, final String value) {
        put(key, value, getDefaultSpUtils());
    }

    /**
     * 提交map,一次性commit,減少頻繁讀寫IO
     *
     * @param hashmap 存儲集合
     */
    public static void put(@NotNull final Map<String, Object> hashmap) {
        put(hashmap, getDefaultSpUtils());
    }


    /**
     * Put the string value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void put(@NonNull final String key, final String value, final boolean isCommit) {
        put(key, value, isCommit, getDefaultSpUtils());
    }

    /**
     * 提交map,一次性commit,減少頻繁讀寫IO
     *
     * @param hashmap  存儲集合
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void put(final Map<String, Object> hashmap, final boolean isCommit) {
        put(hashmap, isCommit, getDefaultSpUtils());
    }


    /**
     * Return the string value in sp.
     *
     * @param key The key of sp.
     * @return the string value if sp exists or {@code ""} otherwise
     */
    public static String getString(@NonNull final String key) {
        return getString(key, getDefaultSpUtils());
    }

    /**
     * Return the string value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the string value if sp exists or {@code defaultValue} otherwise
     */
    public static String getString(@NonNull final String key, final String defaultValue) {
        return getString(key, defaultValue, getDefaultSpUtils());
    }


    /**
     * Put the int value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public static void put(@NonNull final String key, final int value) {
        put(key, value, getDefaultSpUtils());
    }

    /**
     * Put the int value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void put(@NonNull final String key, final int value, final boolean isCommit) {
        put(key, value, isCommit, getDefaultSpUtils());
    }

    /**
     * Return the int value in sp.
     *
     * @param key The key of sp.
     * @return the int value if sp exists or {@code -1} otherwise
     */
    public static int getInt(@NonNull final String key) {
        return getInt(key, getDefaultSpUtils());
    }

    /**
     * Return the int value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the int value if sp exists or {@code defaultValue} otherwise
     */
    public static int getInt(@NonNull final String key, final int defaultValue) {
        return getInt(key, defaultValue, getDefaultSpUtils());
    }

    /**
     * Put the long value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public static void put(@NonNull final String key, final long value) {
        put(key, value, getDefaultSpUtils());
    }

    /**
     * Put the long value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void put(@NonNull final String key, final long value, final boolean isCommit) {
        put(key, value, isCommit, getDefaultSpUtils());
    }

    /**
     * Return the long value in sp.
     *
     * @param key The key of sp.
     * @return the long value if sp exists or {@code -1} otherwise
     */
    public static long getLong(@NonNull final String key) {
        return getLong(key, getDefaultSpUtils());
    }

    /**
     * Return the long value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the long value if sp exists or {@code defaultValue} otherwise
     */
    public static long getLong(@NonNull final String key, final long defaultValue) {
        return getLong(key, defaultValue, getDefaultSpUtils());
    }

    /**
     * Put the float value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public static void put(@NonNull final String key, final float value) {
        put(key, value, getDefaultSpUtils());
    }

    /**
     * Put the float value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void put(@NonNull final String key, final float value, final boolean isCommit) {
        put(key, value, isCommit, getDefaultSpUtils());
    }

    /**
     * Return the float value in sp.
     *
     * @param key The key of sp.
     * @return the float value if sp exists or {@code -1f} otherwise
     */
    public static float getFloat(@NonNull final String key) {
        return getFloat(key, getDefaultSpUtils());
    }

    /**
     * Return the float value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the float value if sp exists or {@code defaultValue} otherwise
     */
    public static float getFloat(@NonNull final String key, final float defaultValue) {
        return getFloat(key, defaultValue, getDefaultSpUtils());
    }

    /**
     * Put the boolean value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public static void put(@NonNull final String key, final boolean value) {
        put(key, value, getDefaultSpUtils());
    }

    /**
     * Put the boolean value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void put(@NonNull final String key, final boolean value, final boolean isCommit) {
        put(key, value, isCommit, getDefaultSpUtils());
    }

    /**
     * Return the boolean value in sp.
     *
     * @param key The key of sp.
     * @return the boolean value if sp exists or {@code false} otherwise
     */
    public static boolean getBoolean(@NonNull final String key) {
        return getBoolean(key, getDefaultSpUtils());
    }

    /**
     * Return the boolean value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the boolean value if sp exists or {@code defaultValue} otherwise
     */
    public static boolean getBoolean(@NonNull final String key, final boolean defaultValue) {
        return getBoolean(key, defaultValue, getDefaultSpUtils());
    }

    /**
     * Put the set of string value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public static void put(@NonNull final String key, final Set<String> value) {
        put(key, value, getDefaultSpUtils());
    }

    /**
     * Put the set of string value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void put(@NonNull final String key,
                           final Set<String> value,
                           final boolean isCommit) {
        put(key, value, isCommit, getDefaultSpUtils());
    }

    /**
     * Return the set of string value in sp.
     *
     * @param key The key of sp.
     * @return the set of string value if sp exists
     * or {@code Collections.<String>emptySet()} otherwise
     */
    public static Set<String> getStringSet(@NonNull final String key) {
        return getStringSet(key, getDefaultSpUtils());
    }

    /**
     * Return the set of string value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the set of string value if sp exists or {@code defaultValue} otherwise
     */
    public static Set<String> getStringSet(@NonNull final String key,
                                           final Set<String> defaultValue) {
        return getStringSet(key, defaultValue, getDefaultSpUtils());
    }

    /**
     * Return all values in sp.
     *
     * @return all values in sp
     */
    public static Map<String, ?> getAll() {
        return getAll(getDefaultSpUtils());
    }

    /**
     * Return whether the sp contains the preference.
     *
     * @param key The key of sp.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean contains(@NonNull final String key) {
        return contains(key, getDefaultSpUtils());
    }

    /**
     * Remove the preference in sp.
     *
     * @param key The key of sp.
     */
    public static void remove(@NonNull final String key) {
        remove(key, getDefaultSpUtils());
    }

    /**
     * Remove the preference in sp.
     *
     * @param key      The key of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void remove(@NonNull final String key, final boolean isCommit) {
        remove(key, isCommit, getDefaultSpUtils());
    }

    /**
     * Remove all preferences in sp.
     */
    public static void clear() {
        clear(getDefaultSpUtils());
    }

    /**
     * Remove all preferences in sp.
     *
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public static void clear(final boolean isCommit) {
        clear(isCommit, getDefaultSpUtils());
    }

    ///////////////////////////////////////////////////////////////////////////
    // dividing line
    ///////////////////////////////////////////////////////////////////////////

    /**
     * Put the string value in sp.
     *
     * @param key     The key of sp.
     * @param value   The value of sp.
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key, final String value, @NonNull final SpUtils spUtils) {
        spUtils.put(key, value);
    }

    /**
     * 一次性提交
     *
     * @param map 存儲集合
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final Map<String, Object> map, @NonNull final SpUtils spUtils) {
        spUtils.put(map);
    }

    /**
     * Put the string value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key,
                           final String value,
                           final boolean isCommit,
                           @NonNull final SpUtils spUtils) {
        spUtils.put(key, value, isCommit);
    }

    /**
     * 一次性提交
     *
     * @param map  存儲集合
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final Map<String, Object> map, final boolean isCommit, @NonNull final SpUtils spUtils) {
        spUtils.put(map, isCommit);
    }

    /**
     * Return the string value in sp.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     * @return the string value if sp exists or {@code ""} otherwise
     */
    public static String getString(@NonNull final String key, @NonNull final SpUtils spUtils) {
        return spUtils.getString(key);
    }

    /**
     * Return the string value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @param spUtils      The instance of {@link SpUtils}.
     * @return the string value if sp exists or {@code defaultValue} otherwise
     */
    public static String getString(@NonNull final String key,
                                   final String defaultValue,
                                   @NonNull final SpUtils spUtils) {
        return spUtils.getString(key, defaultValue);
    }


    /**
     * Put the int value in sp.
     *
     * @param key     The key of sp.
     * @param value   The value of sp.
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key, final int value, @NonNull final SpUtils spUtils) {
        spUtils.put(key, value);
    }

    /**
     * Put the int value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key,
                           final int value,
                           final boolean isCommit,
                           @NonNull final SpUtils spUtils) {
        spUtils.put(key, value, isCommit);
    }

    /**
     * Return the int value in sp.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     * @return the int value if sp exists or {@code -1} otherwise
     */
    public static int getInt(@NonNull final String key, @NonNull final SpUtils spUtils) {
        return spUtils.getInt(key);
    }

    /**
     * Return the int value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @param spUtils      The instance of {@link SpUtils}.
     * @return the int value if sp exists or {@code defaultValue} otherwise
     */
    public static int getInt(@NonNull final String key, final int defaultValue, @NonNull final SpUtils spUtils) {
        return spUtils.getInt(key, defaultValue);
    }

    /**
     * Put the long value in sp.
     *
     * @param key     The key of sp.
     * @param value   The value of sp.
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key, final long value, @NonNull final SpUtils spUtils) {
        spUtils.put(key, value);
    }

    /**
     * Put the long value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key,
                           final long value,
                           final boolean isCommit,
                           @NonNull final SpUtils spUtils) {
        spUtils.put(key, value, isCommit);
    }

    /**
     * Return the long value in sp.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     * @return the long value if sp exists or {@code -1} otherwise
     */
    private static long getLong(@NonNull final String key, @NonNull final SpUtils spUtils) {
        return spUtils.getLong(key);
    }

    /**
     * Return the long value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @param spUtils      The instance of {@link SpUtils}.
     * @return the long value if sp exists or {@code defaultValue} otherwise
     */
    private static long getLong(@NonNull final String key, final long defaultValue, @NonNull final SpUtils spUtils) {
        return spUtils.getLong(key, defaultValue);
    }

    /**
     * Put the float value in sp.
     *
     * @param key     The key of sp.
     * @param value   The value of sp.
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key, final float value, @NonNull final SpUtils spUtils) {
        spUtils.put(key, value);
    }

    /**
     * Put the float value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key,
                           final float value,
                           final boolean isCommit,
                           @NonNull final SpUtils spUtils) {
        spUtils.put(key, value, isCommit);
    }

    /**
     * Return the float value in sp.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     * @return the float value if sp exists or {@code -1f} otherwise
     */
    private static float getFloat(@NonNull final String key, @NonNull final SpUtils spUtils) {
        return spUtils.getFloat(key);
    }

    /**
     * Return the float value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @param spUtils      The instance of {@link SpUtils}.
     * @return the float value if sp exists or {@code defaultValue} otherwise
     */
    private static float getFloat(@NonNull final String key, final float defaultValue, @NonNull final SpUtils spUtils) {
        return spUtils.getFloat(key, defaultValue);
    }

    /**
     * Put the boolean value in sp.
     *
     * @param key     The key of sp.
     * @param value   The value of sp.
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key, final boolean value, @NonNull final SpUtils spUtils) {
        spUtils.put(key, value);
    }

    /**
     * Put the boolean value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key,
                           final boolean value,
                           final boolean isCommit,
                           @NonNull final SpUtils spUtils) {
        spUtils.put(key, value, isCommit);
    }

    /**
     * Return the boolean value in sp.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     * @return the boolean value if sp exists or {@code false} otherwise
     */
    public static boolean getBoolean(@NonNull final String key, @NonNull final SpUtils spUtils) {
        return spUtils.getBoolean(key);
    }

    /**
     * Return the boolean value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @param spUtils      The instance of {@link SpUtils}.
     * @return the boolean value if sp exists or {@code defaultValue} otherwise
     */
    public static boolean getBoolean(@NonNull final String key,
                                     final boolean defaultValue,
                                     @NonNull final SpUtils spUtils) {
        return spUtils.getBoolean(key, defaultValue);
    }

    /**
     * Put the set of string value in sp.
     *
     * @param key     The key of sp.
     * @param value   The value of sp.
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key, final Set<String> value, @NonNull final SpUtils spUtils) {
        spUtils.put(key, value);
    }

    /**
     * Put the set of string value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void put(@NonNull final String key,
                           final Set<String> value,
                           final boolean isCommit,
                           @NonNull final SpUtils spUtils) {
        spUtils.put(key, value, isCommit);
    }

    /**
     * Return the set of string value in sp.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     * @return the set of string value if sp exists
     * or {@code Collections.<String>emptySet()} otherwise
     */
    private static Set<String> getStringSet(@NonNull final String key, @NonNull final SpUtils spUtils) {
        return spUtils.getStringSet(key);
    }

    /**
     * Return the set of string value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @param spUtils      The instance of {@link SpUtils}.
     * @return the set of string value if sp exists or {@code defaultValue} otherwise
     */
    private static Set<String> getStringSet(@NonNull final String key,
                                            final Set<String> defaultValue,
                                            @NonNull final SpUtils spUtils) {
        return spUtils.getStringSet(key, defaultValue);
    }

    /**
     * Return all values in sp.
     *
     * @param spUtils The instance of {@link SpUtils}.
     * @return all values in sp
     */
    private static Map<String, ?> getAll(@NonNull final SpUtils spUtils) {
        return spUtils.getAll();
    }

    /**
     * Return whether the sp contains the preference.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean contains(@NonNull final String key, @NonNull final SpUtils spUtils) {
        return spUtils.contains(key);
    }

    /**
     * Remove the preference in sp.
     *
     * @param key     The key of sp.
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void remove(@NonNull final String key, @NonNull final SpUtils spUtils) {
        spUtils.remove(key);
    }

    /**
     * Remove the preference in sp.
     *
     * @param key      The key of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void remove(@NonNull final String key, final boolean isCommit, @NonNull final SpUtils spUtils) {
        spUtils.remove(key, isCommit);
    }

    /**
     * Remove all preferences in sp.
     *
     * @param spUtils The instance of {@link SpUtils}.
     */
    public static void clear(@NonNull final SpUtils spUtils) {
        spUtils.clear();
    }

    /**
     * Remove all preferences in sp.
     *
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     * @param spUtils  The instance of {@link SpUtils}.
     */
    public static void clear(final boolean isCommit, @NonNull final SpUtils spUtils) {
        spUtils.clear(isCommit);
    }

    /**
     * 獲取簡單存儲工具類 SpUtils
     *
     * @return SpUtils
     */
    private static SpUtils getDefaultSpUtils() {
        return sDefaultSpUtils != null ? sDefaultSpUtils : SpUtils.getInstance(getApplicationByReflect());
    }

    /**
     * 如果你沒有初始化該工具類祝迂,那么我會通過反射獲取當(dāng)前的applicationContext()
     *
     * @return Application
     */
    private static Application getApplicationByReflect() {
        try {
            @SuppressLint("PrivateApi")
            Class<?> activityThread = Class.forName("android.app.ActivityThread");
            Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
            Object app = activityThread.getMethod("getApplication").invoke(thread);
            if (app == null) {
                throw new NullPointerException("u should init first");
            }
            return (Application) app;
        } catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException | InvocationTargetException e) {
            e.printStackTrace();
        }
        throw new NullPointerException("u should init first");
    }
}
public class SpUtils {
    private static final Map<String, SpUtils> SP_UTILS_MAP = new HashMap<>();
    private SharedPreferences sp;

    /**
     * Return the single {@link SpUtils} instance
     *
     * @param context context
     * @return the single {@link SpUtils} instance
     */
    public static SpUtils getInstance(Context context) {
        return getInstance(context, "", Context.MODE_PRIVATE);
    }

    /**
     * Return the single {@link SpUtils} instance
     *
     * @param context context
     * @param mode    Operating mode.
     * @return the single {@link SpUtils} instance
     */
    public static SpUtils getInstance(Context context, final int mode) {
        return getInstance(context, "", mode);
    }

    /**
     * Return the single {@link SpUtils} instance
     *
     * @param context context
     * @param spName  The name of sp.
     * @return the single {@link SpUtils} instance
     */
    public static SpUtils getInstance(Context context, String spName) {
        return getInstance(context, spName, Context.MODE_PRIVATE);
    }

    /**
     * Return the single {@link SpUtils} instance
     *
     * @param context context
     * @param spName  The name of sp.
     * @param mode    Operating mode.
     * @return the single {@link SpUtils} instance
     */
    public static SpUtils getInstance(Context context, String spName, final int mode) {
        if (context == null) {
            throw new UnsupportedOperationException("context can't empty, please init me in SpHelpUtils.class");
        }
        if (isSpace(spName)) {
            spName = context.getPackageName() + "_preferences";
        }
        SpUtils spUtils = SP_UTILS_MAP.get(spName);
        if (spUtils == null) {
            synchronized (SpUtils.class) {
                spUtils = SP_UTILS_MAP.get(spName);
                if (spUtils == null) {
                    spUtils = new SpUtils(context, spName, mode);
                    SP_UTILS_MAP.put(spName, spUtils);
                }
            }
        }
        return spUtils;
    }

    private SpUtils(Context context, final String spName) {
        sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE);
    }

    private SpUtils(final Context context, final String spName, final int mode) {
        sp = context.getSharedPreferences(spName, mode);
    }

    /**
     * Put the string value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public void put(@NonNull final String key, final String value) {
        // TODO 由于項目的功能需求,這個地方標(biāo)志位統(tǒng)一改為走commit方式,后期需要逐一優(yōu)化成apply
        put(key, value, true);
    }

    /**
     * 提交Map結(jié)合器净,用于一次性的commit或者apply型雳,減少平凡讀寫IO
     *
     * @param map 存儲集合
     */
    public void put(@NonNull final Map<String, Object> map) {
        put(map, true);
    }

    /**
     * Put the string value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void put(@NonNull final String key, final String value, final boolean isCommit) {
        if (isCommit) {
            sp.edit().putString(key, value).commit();
        } else {
            sp.edit().putString(key, value).apply();
        }
    }

    /**
     * @param map      存儲集合
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void put(@NonNull final Map<String, Object> map, final boolean isCommit) {
        SharedPreferences.Editor edit = sp.edit();
        for (Map.Entry<String, Object> next : map.entrySet()) {
            if (next.getValue() instanceof String) {
                edit.putString(next.getKey(), String.valueOf(next.getValue()));
            } else if (next.getValue() instanceof Boolean) {
                edit.putBoolean(next.getKey(), (Boolean) next.getValue());
            } else if (next.getValue() instanceof Integer) {
                edit.putInt(next.getKey(), (Integer) next.getValue());
            } else if (next.getValue() instanceof Float) {
                edit.putFloat(next.getKey(), (Float) next.getValue());
            } else if (next.getValue() instanceof Long) {
                edit.putLong(next.getKey(), (Long) next.getValue());
            } else {
                throw new UnsupportedOperationException("parameter Unsupported type!");
            }
        }
        if (isCommit) {
            edit.commit();
        } else {
            edit.apply();
        }
    }

    /**
     * Return the string value in sp.
     *
     * @param key The key of sp.
     * @return the string value if sp exists or {@code ""} otherwise
     */
    public String getString(@NonNull final String key) {
        return getString(key, "");
    }

    /**
     * Return the string value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the string value if sp exists or {@code defaultValue} otherwise
     */
    public String getString(@NonNull final String key, final String defaultValue) {
        return sp.getString(key, defaultValue);
    }

    /**
     * Put the int value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public void put(@NonNull final String key, final int value) {
        put(key, value, false);
    }

    /**
     * Put the int value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void put(@NonNull final String key, final int value, final boolean isCommit) {
        if (isCommit) {
            sp.edit().putInt(key, value).commit();
        } else {
            sp.edit().putInt(key, value).apply();
        }
    }

    /**
     * Return the int value in sp.
     *
     * @param key The key of sp.
     * @return the int value if sp exists or {@code -1} otherwise
     */
    public int getInt(@NonNull final String key) {
        return getInt(key, -1);
    }

    /**
     * Return the int value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the int value if sp exists or {@code defaultValue} otherwise
     */
    public int getInt(@NonNull final String key, final int defaultValue) {
        return sp.getInt(key, defaultValue);
    }

    /**
     * Put the long value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public void put(@NonNull final String key, final long value) {
        put(key, value, false);
    }

    /**
     * Put the long value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void put(@NonNull final String key, final long value, final boolean isCommit) {
        if (isCommit) {
            sp.edit().putLong(key, value).commit();
        } else {
            sp.edit().putLong(key, value).apply();
        }
    }

    /**
     * Return the long value in sp.
     *
     * @param key The key of sp.
     * @return the long value if sp exists or {@code -1} otherwise
     */
    public long getLong(@NonNull final String key) {
        return getLong(key, -1L);
    }

    /**
     * Return the long value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the long value if sp exists or {@code defaultValue} otherwise
     */
    public long getLong(@NonNull final String key, final long defaultValue) {
        return sp.getLong(key, defaultValue);
    }

    /**
     * Put the float value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public void put(@NonNull final String key, final float value) {
        put(key, value, false);
    }

    /**
     * Put the float value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void put(@NonNull final String key, final float value, final boolean isCommit) {
        if (isCommit) {
            sp.edit().putFloat(key, value).commit();
        } else {
            sp.edit().putFloat(key, value).apply();
        }
    }

    /**
     * Return the float value in sp.
     *
     * @param key The key of sp.
     * @return the float value if sp exists or {@code -1f} otherwise
     */
    public float getFloat(@NonNull final String key) {
        return getFloat(key, -1f);
    }

    /**
     * Return the float value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the float value if sp exists or {@code defaultValue} otherwise
     */
    public float getFloat(@NonNull final String key, final float defaultValue) {
        return sp.getFloat(key, defaultValue);
    }

    /**
     * Put the boolean value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public void put(@NonNull final String key, final boolean value) {
        put(key, value, false);
    }

    /**
     * Put the boolean value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void put(@NonNull final String key, final boolean value, final boolean isCommit) {
        if (isCommit) {
            sp.edit().putBoolean(key, value).commit();
        } else {
            sp.edit().putBoolean(key, value).apply();
        }
    }

    /**
     * Return the boolean value in sp.
     *
     * @param key The key of sp.
     * @return the boolean value if sp exists or {@code false} otherwise
     */
    public boolean getBoolean(@NonNull final String key) {
        return getBoolean(key, false);
    }

    /**
     * Return the boolean value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the boolean value if sp exists or {@code defaultValue} otherwise
     */
    public boolean getBoolean(@NonNull final String key, final boolean defaultValue) {
        return sp.getBoolean(key, defaultValue);
    }

    /**
     * Put the set of string value in sp.
     *
     * @param key   The key of sp.
     * @param value The value of sp.
     */
    public void put(@NonNull final String key, final Set<String> value) {
        put(key, value, false);
    }

    /**
     * Put the set of string value in sp.
     *
     * @param key      The key of sp.
     * @param value    The value of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void put(@NonNull final String key,
                    final Set<String> value,
                    final boolean isCommit) {
        if (isCommit) {
            sp.edit().putStringSet(key, value).commit();
        } else {
            sp.edit().putStringSet(key, value).apply();
        }
    }

    /**
     * Return the set of string value in sp.
     *
     * @param key The key of sp.
     * @return the set of string value if sp exists
     * or {@code Collections.<String>emptySet()} otherwise
     */
    public Set<String> getStringSet(@NonNull final String key) {
        return getStringSet(key, Collections.emptySet());
    }

    /**
     * Return the set of string value in sp.
     *
     * @param key          The key of sp.
     * @param defaultValue The default value if the sp doesn't exist.
     * @return the set of string value if sp exists or {@code defaultValue} otherwise
     */
    public Set<String> getStringSet(@NonNull final String key,
                                    final Set<String> defaultValue) {
        return sp.getStringSet(key, defaultValue);
    }

    /**
     * Return all values in sp.
     *
     * @return all values in sp
     */
    public Map<String, ?> getAll() {
        return sp.getAll();
    }

    /**
     * Return whether the sp contains the preference.
     *
     * @param key The key of sp.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public boolean contains(@NonNull final String key) {
        return sp.contains(key);
    }

    /**
     * Remove the preference in sp.
     *
     * @param key The key of sp.
     */
    public void remove(@NonNull final String key) {
        remove(key, false);
    }

    /**
     * Remove the preference in sp.
     *
     * @param key      The key of sp.
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void remove(@NonNull final String key, final boolean isCommit) {
        if (isCommit) {
            sp.edit().remove(key).commit();
        } else {
            sp.edit().remove(key).apply();
        }
    }

    /**
     * Remove all preferences in sp.
     */
    public void clear() {
        clear(false);
    }

    /**
     * Remove all preferences in sp.
     *
     * @param isCommit True to use {@link SharedPreferences.Editor#commit()},
     *                 false to use {@link SharedPreferences.Editor#apply()}
     */
    public void clear(final boolean isCommit) {
        if (isCommit) {
            sp.edit().clear().commit();
        } else {
            sp.edit().clear().apply();
        }
    }

    private static boolean isSpace(final String s) {
        if (s == null) {
            return true;
        }
        for (int i = 0, len = s.length(); i < len; ++i) {
            if (!Character.isWhitespace(s.charAt(i))) {
                return false;
            }
        }
        return true;
    }
}

寫在最后

感謝各位大佬的閱讀,如果存在不足的地方或者有更好的建議山害,請留言回復(fù)纠俭,我會盡量把文章的質(zhì)量做到更好以分享給更多的讀者,謝謝浪慌!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冤荆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子权纤,更是在濱河造成了極大的恐慌钓简,老刑警劉巖乌妒,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異外邓,居然都是意外死亡撤蚊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門损话,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拴魄,“玉大人,你說我怎么就攤上這事席镀∑ブ校” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵豪诲,是天一觀的道長顶捷。 經(jīng)常有香客問我,道長屎篱,這世上最難降的妖魔是什么服赎? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮交播,結(jié)果婚禮上重虑,老公的妹妹穿的比我還像新娘。我一直安慰自己秦士,他們只是感情好缺厉,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著隧土,像睡著了一般提针。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上曹傀,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天辐脖,我揣著相機與錄音,去河邊找鬼皆愉。 笑死嗜价,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的幕庐。 我是一名探鬼主播久锥,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼翔脱!你這毒婦竟也來了奴拦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤届吁,失蹤者是張志新(化名)和其女友劉穎错妖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疚沐,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡暂氯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亮蛔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痴施。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖究流,靈堂內(nèi)的尸體忽然破棺而出辣吃,到底是詐尸還是另有隱情,我是刑警寧澤芬探,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布神得,位于F島的核電站,受9級特大地震影響偷仿,放射性物質(zhì)發(fā)生泄漏哩簿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一酝静、第九天 我趴在偏房一處隱蔽的房頂上張望节榜。 院中可真熱鬧,春花似錦别智、人聲如沸宗苍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浓若。三九已至,卻和暖如春蛇数,著一層夾襖步出監(jiān)牢的瞬間挪钓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工耳舅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碌上,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓浦徊,卻偏偏與公主長得像馏予,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子盔性,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容