Android数据持久化之SharedPreference

概念

SharedPreference是Android上一种非常易用的轻量级存储方式,只能存放Boolean,Float,Int,Long,String 五种类型,数据存储在Android系统的 /data/data/应用包名/shared_prefs 目录下的.xml文件,用户应用程序一旦卸载,存在应用数据目录下的shared_prefs文件也会被删除。

使用方式

1.创建SharedPreference,如果存在目标文件,则打开并加载到内存以map格式存在,否则创建。有三种方式可以来获取:

  • 方式一
    Activity#getPreferences
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
    return mBase.getSharedPreferences(name, mode);
}

创建的xml文件名字就是name.xml,也就是说不同的name会生成不同的.xml文件。

  • 方式二
    PreferenceManager#getDefaultSharedPreferences
public static SharedPreferences getDefaultSharedPreferences(Context context) {
    return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
            getDefaultSharedPreferencesMode());
}

创建的文件名字为:应用包名_preferences.xml

  • 方式三
    ContextImpl#getSharedPreferences
@Override
public SharedPreferences getSharedPreferences(File file, int mode) {
  ...
}

2.存放数据,异步提交;读取数据

//存放数据
Editor editor = preference.edit(); 
editor.putBoolean("test",true);
editor.apply();//editor.commit();
//读取数据
preference.getBoolean("test",false);

我们来看一下存储的文件内容

每一个存储都是map标签下的一对key-value

以上就是SharedPreference最基本也是常见的使用。一般使用SharedPreference不会出现什么问题,但是还是需要几点注意的地方。

注意事项

  1. getSharedPreferences操作是将存储数据的目标(name.xml)文件创建,并且在内存中创建map结构容器或者从已创建的目标文件中读取数据加载到内存map结构中,这个文件不宜过大,在获取目标数据(get过程)前需要等待读取文件内容完毕,过大的话这个时间会长一些。

2.尽量避免重复getSharedPreferences同一个名称的.xml(也就是同一个文件),毕竟读取文件的过程还是有一定的资源花费。

3.不要put一个就apply或者commit一次,apply和commit是将保存在map容器中的数据写入.xml中,IO操作还是会耗费一定的资源的。

工具类(一般项目缓存的数据不会很多)

import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import com.floruit.fruitsvideo.App;

import java.util.Map;

/**
 * 缓存工具类
 */
public class SpUtil {

    public static final String USERID = "user_id";
    public static final String AVATAR = "avatar";
    public static final String NICKNAME = "nick";

    private static SpUtil INSTANCE;

    private SharedPreferences sharedPreferences;
    private SharedPreferences.Editor editor;

    private SpUtil() {
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(App.getApplication());
        editor = sharedPreferences.edit();
    }

    public static SpUtil getInstance() {
        if (INSTANCE == null) {
            synchronized (SpUtil.class) {
                if (INSTANCE == null) {
                    INSTANCE = new SpUtil();
                }
            }
        }
        return INSTANCE;
    }

    /**
     * 获取保存的数据
     */
    public Object getSharedPreference(String key, Object defaultObject) {
        if (defaultObject instanceof String) {
            return sharedPreferences.getString(key, (String) defaultObject);
        } else if (defaultObject instanceof Integer) {
            return sharedPreferences.getInt(key, (Integer) defaultObject);
        } else if (defaultObject instanceof Boolean) {
            return sharedPreferences.getBoolean(key, (Boolean) defaultObject);
        } else if (defaultObject instanceof Float) {
            return sharedPreferences.getFloat(key, (Float) defaultObject);
        } else if (defaultObject instanceof Long) {
            return sharedPreferences.getLong(key, (Long) defaultObject);
        } else {
            return sharedPreferences.getString(key, null);
        }
    }

    public String getString(String key) {
        return sharedPreferences.getString(key, "");
    }

    public boolean getBoolean(String key){
        return sharedPreferences.getBoolean(key,false);
    }

    public int getInt(String key){
        return sharedPreferences.getInt(key,0);
    }

    /**
     * 存储
     */
    public void put(String key, Object object) {
        if (object instanceof String) {
            editor.putString(key, (String) object);
        } else if (object instanceof Integer) {
            editor.putInt(key, (Integer) object);
        } else if (object instanceof Boolean) {
            editor.putBoolean(key, (Boolean) object);
        } else if (object instanceof Float) {
            editor.putFloat(key, (Float) object);
        } else if (object instanceof Long) {
            editor.putLong(key, (Long) object);
        } else {
            editor.putString(key, object.toString());
        }
    }
    
    /**
     * 移除某个key值已经对应的值
     */
    public void remove(String key) {
        editor.remove(key);
    }

    /**
     * 清除所有数据
     */
    public void clear() {
        editor.clear();
        editor.apply();
    }

    /**
     * 统一写入缓存文件
     * 异步
     */
    public void apply(){
        editor.apply();
    }

    /**
     * 统一写入混存文件
     * 同步
     */
    public void commit(){
        editor.commit();
    }

    /**
     * 查询某个key是否存在
     */
    public Boolean contain(String key) {
        return sharedPreferences.contains(key);
    }

    /**
     * 返回所有的键值对
     */
    public Map<String, ?> getAll() {
        return sharedPreferences.getAll();
    }
}

(1)在工具类中统一定义静态常量key值,以免多次使用书写错误。
(2)使用单例获取SharedPreference和Editor,在这个过程中内存中生成了map容器。
(3)通常情况缓存时不单单会缓存一个值,所以我们单独apply或者commit。

更多

SharedPreference中还有像xml文件数据在内存中的map容器,备份文件等概念,这里不再一一细说,很多分析原理的文章,下面列出几篇。

相关文章:
SharedPreference 源码分析
谈一谈SharedPreference的一些使用误区
Android之不要滥用SharedPreferences(上)
Android 之不要滥用 SharedPreferences(下)

推荐阅读更多精彩内容