SharedPreferences在项目中应用——开发记录

开发记录:在日常开发中,长使用的几种本地序列化方式,SP的使用是最普遍的,所以对SP 的封装就异常重要了,用起来顺手的SP封装工具,能够节省你很多时间。

  1. 面试技能点
  2. 原生代码实现
  3. 工具类(只想要代码 Github 三个类直接贴到项目中就行了。

枯燥的原理时间:

1. SharedPreferences读取xml文件时,会以DOM方式解析(把整个xml文件直接加载到内存中解析),在调用getXXX()方法时取到的是内存中的数据,方法执行时会有个锁来阻塞,目的是等待文件加载完毕,没加载完成之前会wait()。

2. SharedPreferences写文件时,如果调用的commit(),会将数据同步写入内存中,内存数据更新,再同步写入磁盘中;如果调用的apply(),会将数据同步写入内存中,内存数据更新,然后异步写人磁盘,也就是说可能写磁盘操作还没有完成就直接返回了。在主线程中建议使用apply(),因为同步写磁盘,当文件较大时,commit()会等到写磁盘完成再返回,可能会有ANR问题。

3. SP第一次初始化到读取到数据存在一定延迟,因为需要到文件中读取数据,因此可能会对UI线程流畅度造成一定影响。

原生实现:

//获得SharedPreferences的实例 sp_name是文件名
SharedPreferences sp = getSharedPreferences("sp_name", Context.MODE_PRIVATE);

//获得Editor 实例
SharedPreferences.Editor editor = sp.edit();

//以key-value形式保存数据
editor.putString("data_key", "data");

//apply()是异步写入数据
editor.apply();   

//commit()是同步写入数据 
//editor.commit(); 

PrefsHelper: SP 封装类
public class PrefsHelper {
    //保存文件名称
    private static final String PREFERENCE_FILE_NAME = "Example";
    //用户个人的信息
    private static final String KEY_USER_INFO = "UserInfo";

    // 注册
    public static void init(Context context) {
        Prefs.init(context.getApplicationContext(), PREFERENCE_FILE_NAME);
    }

    /**
     * 保存用户的登录数据。
     */
    public static void setUserInfo(@NonNull UserBean info) {
        String infoToSave = new Gson().toJson(info);
        LogUtil.d("UserBeanToSp:%s" + infoToSave);
        Prefs.set(KEY_USER_INFO, infoToSave);
    }

    /**
     * 获取用户的个人信息。
     */
    @Nullable
    public static UserBean getUserInfo() {
        String savedInfo = Prefs.getString(KEY_USER_INFO);
        if (TextUtils.isEmpty(savedInfo)) {
            return null;
        }
        return new Gson().fromJson(savedInfo, UserBean.class);
    }

    /**
     * 清除用户登录数据。
     */
    public static void removeLoginInfo() {
        LogUtil.d("Removing UserBean info.");
        Prefs.remove(KEY_USER_INFO);
    }
}
Prefs:SP 具体操作类
/* package */ class Prefs {
    private static Context appContext;
    private static String fileName;

    /**
     * 为后续调用初始化此类.
     * @param context 上下文.
     * @param file SP的文件读写.
     */
    public static void init(@NonNull Context context, @NonNull String file){
        appContext = context.getApplicationContext();
        fileName = file;
    }

    /**
     *检索SP值,假设第二个参数是正确的类.
     * @param <T> 支持类型Boolean, Integer, Long, Float, Double, String,不支持类型会抛出
     */
    @SuppressWarnings("unchecked")
    public static <T> T get(@NonNull String key, T fallback) throws
            UnsupportedOperationException {
        SharedPreferences sp = getSharedPreferences();
        Object result;
        if (fallback instanceof Boolean){
            result = sp.getBoolean(key, (Boolean)fallback);
        }
        else if (fallback instanceof String){
            result = sp.getString(key, (String) fallback);
        }
        else if (fallback instanceof Integer){
            result = sp.getInt(key, (Integer) fallback);
        }
        else if (fallback instanceof Float){
            result = sp.getFloat(key, (Float) fallback);
        }
        else if (fallback instanceof Long) {
            result = sp.getLong(key, (Long) fallback);
        }
        else{
            throw new UnsupportedOperationException("Type not supported: " + fallback.getClass()
                    .getSimpleName());
        }
        return (T)result;
    }

    /**
     * 从首选项中检索字符串值,默认值为空字符串。.
     */
    public static String getString(@NonNull String key){
        return get(key, "");
    }

    /**
     * 长值检索默认是 0 代码。
     */
    public static long getLong(@NonNull String key){
        return get(key, 0L);
    }

    /**
     * 从首选项中检索整数值, default is <code>0</code>.
     */
    public static int getInt(@NonNull String key){
        return get(key, 0);
    }

    /**
     * 检索一个布尔值, default is <code>false</code>.
     */
    public static boolean getBoolean(@NonNull String key){
        return get(key, false);
    }

    /**
     * 把值放进SP 中
     * @param <T> Boolean, Integer, Long, Float, Double, String allowed. For other types, an
     *           UnsupportedOperationException is thrown.
     */
    public static <T> void set(@NonNull String key, @NonNull T value) {
        SharedPreferences.Editor editor = getSharedPreferences().edit();
        if (value instanceof Boolean){
            editor.putBoolean(key, (Boolean) value);
        }
        else if (value instanceof String){
            editor.putString(key, (String) value);
        }
        else if (value instanceof Integer){
            editor.putInt(key, (Integer) value);
        }
        else if (value instanceof Float){
            editor.putFloat(key, (Float) value);
        }
        else if (value instanceof Long) {
            editor.putLong(key, (Long) value);
        }
        else{
            throw new UnsupportedOperationException("Type not supported: " + value.getClass()
                    .getSimpleName());
        }
        //use apply instead of commit to improve performance on UI thread.
        editor.apply();
    }

    public static void remove(String key) {
        getSharedPreferences().edit().remove(key).apply();
    }

    /**
     * clear all data!
     * @see SharedPreferences.Editor#clear()
     */
    public static void clear(){
        getSharedPreferences().edit().clear().apply();
    }

    private static SharedPreferences getSharedPreferences() {
        checkInitiatedOrThrow();
        return appContext.getSharedPreferences(fileName, Context.MODE_PRIVATE);
    }

    /**
     * Retrieve all values from the preferences.
     * @see SharedPreferences#getAll()
     */
    public static Map<String, ?> getAll(){
        return getSharedPreferences().getAll();
    }

    private static void checkInitiatedOrThrow() {
        if (appContext == null || TextUtils.isEmpty(fileName)) {
            throw new IllegalStateException("The Prefs class is not initialized correctly.");
        }
    }
}
LocalDataManager:单例模式调用 PrefsHelper 
public class LocalDataManager {

    private static LocalDataManager instance;
    private UserBean mUserBean;
    private LocalDataManager() {
        // 私有化构造
    }

    public static LocalDataManager getInstance() {
        if (instance == null) {
            synchronized (LocalDataManager.class) {
                // 线程安全的单利模式
                if (instance == null) {
                    instance = new LocalDataManager();
                }
            }
        }
        return instance;
    }

    /**
     * 获取用户个人信息
     *
     * @return
     */
    public UserBean getUserInfo() {
        if (mUserBean == null) {
            mUserBean = PrefsHelper.getUserInfo();
        }
        return mUserBean;
    }

    /**
     * 获取用户个人信息
     *
     * @return
     */
    public void saveUserInfo(@NonNull UserBean mUserBean) {
        //Update cached object!
        this.mUserBean = mUserBean;
        PrefsHelper.setUserInfo(mUserBean);
    }
    /**
     * 清楚用户信息
     *
     * @return
     */
    public void clearLoginInfo() {
        mUserBean = null;
        PrefsHelper.removeLoginInfo();
    }

}

MianActivity : 具体使用

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化Prefs 建议在Application 中进行初始化
        PrefsHelper.init(this);


        UserBean mUserBean = new UserBean();
        mUserBean.setAll_money(1);
        LocalDataManager.getInstance().saveUserInfo(mUserBean);
        // 一般登录的时候,拿到用户的数据,直接保存在SP 中,或者APP 是否首次登录等判断

        UserBean bean  = LocalDataManager.getInstance().getUserInfo();
        LogUtil.e(bean.getAll_money()+"元");

    }
}


代码拿走,留个赞,互相帮助!!!

下一篇准备写ViewPager +Fragment  懒加载,也是在日常开发中遇到的问题。避免下次采坑。

猜你喜欢

转载自blog.csdn.net/qq_30974087/article/details/81567318