Android SharedPreferences的單例模式(二)

另一個項目中的SP工具類,有時間需要和之前一個工具類整合一下。

import android.content.Context;
import android.content.SharedPreferences;

import androidx.annotation.NonNull;

import com.google.gson.Gson;
import com.guangsu.messenger.MyApplication;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * SharedPreferences極致封裝
 * https://www.jianshu.com/p/895df2258282
 * commit()方法會同步地將偏好值(Preference)直接寫入持久化存儲設備,
 * 而apply()方法會立即把修改內容提交到SharedPreferences內容緩存中,
 * 然後開始異步的將修改提交到存儲設備上,在這個過程中,開發者不會察覺到任何錯誤問題。
 * <p>
 * 這兩個方法的區別在於:
 * 1. apply沒有返回值而commit返回boolean表明修改是否提交成功
 * 2. apply是將修改數據原子提交到內存, 而後異步真正提交到硬件磁盤,
 * 而commit是同步的提交到硬件磁盤,
 * 因此,在多個併發的提交commit的時候,他們會等待正在處理的commit保存到磁盤後在操作,從而降低了效率。
 * 而apply只是原子的提交到內容,後面有調用apply的函數的將會直接覆蓋前面的內存數據,這樣從一定程度上提高了很多效率。
 * 3. apply方法不會提示任何失敗的提示。
 * <p>
 * 由於在一個進程中,sharedPreference是單實例,一般不會出現併發衝突,如果對提交的結果不關心的話,建議使用apply,
 * 當然需要確保提交成功且有後續操作的話,還是需要用commit的。
 */
public class SPUtils {
    //保存在手機裏面的文件名
    public static final String FILE_NAME = "messenger_cache";
    public static SharedPreferences sp;

    private static SharedPreferences init(Context context) {
        return sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
    }

    /**
     * 存
     *
     * @param key   鍵
     * @param value 值
     * @param <E>   泛型,自動根據值進行處理
     */
    public static <E> void put(@NonNull String key, @NonNull E value) {
        put(MyApplication.getInstance(), key, value);
    }

    /**
     * 取
     *
     * @param key          鍵
     * @param defaultValue 默認值
     * @param <E>          泛型,自動根據值進行處理
     * @return
     */
    public static <E> E get(@NonNull String key, @NonNull E defaultValue) {
        return get(MyApplication.getInstance(), key, defaultValue);
    }

    /**
     * 插件間和宿主共用數據 必須 傳入context
     *
     * @param context
     * @param key
     * @param value
     * @return
     */
    public static <E> void put(Context context, @NonNull String key, @NonNull E value) {
        SharedPreferences.Editor editor = init(context).edit();
        if (value instanceof String || value instanceof Integer || value instanceof Boolean ||
                value instanceof Float || value instanceof Long || value instanceof Double) {
            editor.putString(key, String.valueOf(value));
        } else {
            editor.putString(key, new Gson().toJson(value));
        }
        SPCompat.apply(editor);
    }


    /**
     * 插件間和宿主共用數據 必須 傳入context
     *
     * @param key
     * @param defaultValue
     * @return
     */
    public static <E> E get(Context context, @NonNull String key, @NonNull E defaultValue) {
        String value = init(context).getString(key, String.valueOf(defaultValue));
        if (defaultValue instanceof String) {
            return (E) value;
        }
        if (defaultValue instanceof Integer) {
            return (E) Integer.valueOf(value);
        }
        if (defaultValue instanceof Boolean) {
            return (E) Boolean.valueOf(value);
        }
        if (defaultValue instanceof Float) {
            return (E) Float.valueOf(value);
        }
        if (defaultValue instanceof Long) {
            return (E) Long.valueOf(value);
        }
        if (defaultValue instanceof Double) {
            return (E) Double.valueOf(value);
        }
        //json爲null的時候返回對象爲null,gson已處理
        return (E) new Gson().fromJson(value, defaultValue.getClass());
    }


    /**
     * 移除某個key值已經對應的值
     *
     * @param context
     * @param key
     */
    public static void remove(Context context, String key) {
        SharedPreferences.Editor editor = init(context).edit();
        editor.remove(key);
        SPCompat.apply(editor);
    }

    /**
     * 清除所有數據
     *
     * @param context
     */
    public static void clear(Context context) {
        SharedPreferences.Editor editor = init(context).edit();
        editor.clear();
        SPCompat.apply(editor);
    }

    /**
     * 查詢某個key是否已經存在
     *
     * @param context
     * @param key
     * @return
     */
    public static boolean contains(Context context, String key) {
        return init(context).contains(key);
    }

    public static boolean contains(String key) {
        return contains(MyApplication.getInstance(), key);
    }

    /**
     * 返回所有的鍵值對
     *
     * @param context
     * @return
     */
    public static Map<String, ?> getAll(Context context) {
        return init(context).getAll();
    }

    /**
     * 保存對象到sp文件中 被保存的對象須要實現 Serializable 接口
     *
     * @param key
     * @param value
     */
    public static void saveObject(String key, Object value) {
        put(key, value);
    }

    /**
     * desc:獲取保存的Object對象
     *
     * @param key
     * @return modified:
     */
    public static <T> T readObject(String key, Class<T> clazz) {
        try {
            return get(key, clazz.newInstance());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 創建一個解決SharedPreferencesCompat.apply方法的一個兼容類
     *
     * @author
     */
    private static class SPCompat {
        private static final Method S_APPLY_METHOD = findApplyMethod();

        /**
         * 反射查找apply的方法
         *
         * @return
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static Method findApplyMethod() {
            try {
                Class clz = SharedPreferences.Editor.class;
                return clz.getMethod("apply");
            } catch (NoSuchMethodException e) {

            }
            return null;
        }

        /**
         * 如果找到則使用apply執行,否則使用commit
         *
         * @param editor
         */
        public static void apply(SharedPreferences.Editor editor) {
            try {
                if (S_APPLY_METHOD != null) {
                    S_APPLY_METHOD.invoke(editor);
                    return;
                }
            } catch (Exception e) {

            }
            editor.commit();
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章