1,概念
SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,以XML文件的形式存储的键值对(key-value)数据的数据存储方式保存在 /data/data/PACKAGE_NAME/shared_prefs目录下。
2,场景
一般用于储存应用的配置等信息。
注意:SharedPreferences文件并不安全,手机root后即可查看其信息,请勿存储用户信息、密码等敏感信息。(可以不存放密码,存放用户名,登录时检测有用户名则直接登录,可限定日期)
1)少量数据的保存
2)数据格式简单(基本数据类型)
如配置信息(是否打开音效、是否使用震动效果)、游戏的积分信息。
如各个界面需要相互传递的信息(用户名、用户头像修改、传值过于麻烦,直接存储在SharedPreferences中)
3)通过key-value的方式保存数据
3,实现
1)SharePreferences对象
通过Context上下文获取。
SharedPreferences preferences=getSharedPreferences("user",Context.MODE_PRIVATE);
--Use 0 or MODE_PRIVATE 默认设置,只能被本应用读写
--MODE_WORLD_READABLE 被其他应用程序读,不可写
--MODE_WORLD_WRITEABLE 被其他应用程序读写
2)Editor对象
调用SharePreferences的edit()方法返回一个Editor对象。
abstract SharedPreferences.Editor edit()
Editor editor=preferences.edit();
3)设置数据
通过Editor的putXXX(key , value)方法。
String name="xixi";
String age="22";
editor.putString("name", name);
editor.putString("age", age);
4)关闭对象
通过Editor的 commit(); 方法。
editor.commit();//返回boolean
5)其他
contains(String key) 判定SharedPreference是否包含key对应的值
Map<String, ?> getAll() 获取SharePreference里面全部的数据对
SharedPreferences.Editor remove(String key) 移除
SharedPreferences.Editor clear() 清除所有的数据
4,优缺点
1)优点
①可以全局共享访问
②对于常规的轻量级而言比SQLite好一点。
当存储量不大的时候可以考虑自己定义文件格式。
2)缺点
①保存为xml文件,整体效率来看不是特别的高,但却高于SQLit
xml处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好。
②安全性较差,请勿保存敏感信息
③对于较大的存储文件,会造成界面卡顿
SharedPreference在创建时会把整个文件全部加载进内存,如果文件较大,会出现以下问题:
i>第一次从sp中获取值的时候,有可能阻塞主线程,使界面卡顿、掉帧。
ii>解析sp的时候会产生大量的临时对象,导致频繁GC,引起界面卡顿。
iii>这些key和value会永远存在于内存之中,占用大量内存。
5,安全性
1)开发者在创建文件时务必选取合适的创建模式(MODE_PRIVATE、MODE_WORLD_READABLE以及MODE_WORLD_WRITEABLE)进行权限控制。
2)避免使用MODE_WORLD_WRITEABLE和MODE_WORLD_READABLE模式创建进程间通信的文件,此处即为Shared Preferences;如果需要与其他进程应用进行数据共享,请考虑使用content provider。
3)不要在使用“android:sharedUserId”属性的同时,对应用使用测试签名,否则其他应用拥有“android:sharedUserId”属性值和测试签名时,将会访问到内部存储文件数据。
6,优化
1)不要存放大的key和value,会引起界面卡、频繁GC、占用内存等等。
2)毫不相关的配置项就不要放在在一起,文件越大读取越慢。
3)读取频繁的key和不易变动的key尽量不要放在一起,影响速度,如果整个文件很小,那么忽略吧,为了这点性能添加维护成本得不偿失。
4)不要乱edit和apply,尽量批量修改一次提交,多次apply会阻塞主线程。
5)尽量不要存放JSON和HTML,这种场景请直接使用JSON。
6)SharedPreference无法进行跨进程通信,MODE_MULTI_PROCESS只是保证了在API 11以前的系统上,如果sp已经被读取进内存,再次获取这个SharedPreference的时候,如果有这个flag,会重新读一遍文件,仅此而已。
7,demo
1)简单用法
//FILE_BD 保存账户绑定信息
SharedPreferences preferences_BD = null;
String FILE_BD = "saveUserBind";//用于保存账户绑定信息
...
//读入信息
void PutScopeClose(){
if (preferences_BD == null) {
preferences_BD = mContext.getSharedPreferences(FILE_BD, MODE_PRIVATE);
}
Editor editPhone = preferences_BD.edit();
switch (arr[1]) {
case "onebind":
editPhone.putString("Scope_Close1", arr[2]);
break;
case "twobind":
editPhone.putString("Scope_Close2", arr[2]);
break;
}
editPhone.commit();
}
//获取开启关闭安全距离信息
String GetScopeClose(){
String sendStr="";
preferences_BD = mContext.getSharedPreferences(FILE_BD, MODE_PRIVATE);
sendStr = preferences_BD.getString("Scope_Close1", "close") + "," +
preferences_BD.getString("Scope_Close2", "close") + "," + ":end" + ",";
return sendStr;
}
2)封装SharePreferenceUtil
public class SharePreferenceUtil {
public static boolean isLogin(SharedPreferences sp){
return sp.getBoolean("isLogin", false);
}
public static SharedPreferences getSharePerference(Context context){
return context.getSharedPreferences(VariableUtil.APPLICATION_NAME, Context.MODE_PRIVATE);
}
public static void setStringSharedPerference(SharedPreferences sp,String key,String value){
Editor editor=sp.edit();
editor.putString(key, value);
editor.commit();
}
public static void setStrsSharedPerference(SharedPreferences sp,String[] key,String[] value){
Editor editor=sp.edit();
for(int i=0;i<key.length;i++){
editor.putString(key[i], value[i]);
LogUtils.i(tag, " setStrsSharedPerference: " + key[i] + "," + value[i]);
}
editor.commit();
}
public static void removeStrsSharedPerference(SharedPreferences sp,String[] key){
Editor editor=sp.edit();
for(int i=0;i<key.length;i++){
editor.remove(key[i]);
LogUtils.i(tag, " removeStrsSharedPerference: " + key[i]);
}
editor.commit();
}
public static void setBooleanSharedPerference(SharedPreferences sp,String key,boolean value){
Editor editor=sp.edit();
editor.putBoolean(key, value);
editor.commit();
}
/**
* 删除缓存中的图片数据
*/
public static void removeTempFromPref(Context context,String key) {
SharedPreferences sp = context.getSharedPreferences(VariableUtil.APPLICATION_NAME, 0);
sp.edit().remove(key).commit();
}
}
3)封装SPUtils
SPUtils spUtils1 = SPUtils.getInstance(Config.USER_INFO);
spUtils1.put(Config.USER_ID, id);//Config为常量bean
import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
public class SPUtils {
private static Map<String, SPUtils> sSPMap = new HashMap<>();
private SharedPreferences sp;
/**
* 获取SP实例
*
* @return {@link SPUtils}
*/
public static SPUtils getInstance() {
return getInstance("");
}
/**
* 获取SP实例
*
* @param spName sp名
* @return {@link SPUtils}
*/
public static SPUtils getInstance(String spName) {
if (isSpace(spName)) spName = "spUtils";
SPUtils sp = sSPMap.get(spName);
if (sp == null) {
sp = new SPUtils(spName);
sSPMap.put(spName, sp);
}
return sp;
}
private SPUtils(String spName) {
sp = MyApplication.context.getSharedPreferences(spName, Context.MODE_PRIVATE);
}
/**
* SP中写入String
*
* @param key 键
* @param value 值
*/
public void put(@NonNull String key, @NonNull String value) {
sp.edit().putString(key, value).apply();
}
/**
* SP中读取String
*
* @param key 键
* @return 存在返回对应值,不存在返回默认值{@code null}
*/
public String getString(@NonNull String key) {
return getString(key, "");
}
/**
* SP中读取String
*
* @param key 键
* @param defaultValue 默认值
* @return 存在返回对应值,不存在返回默认值{@code defaultValue}
*/
public String getString(@NonNull String key, @NonNull String defaultValue) {
return sp.getString(key, defaultValue);
}
/**
* SP中写入int
*
* @param key 键
* @param value 值
*/
public void put(@NonNull String key, int value) {
sp.edit().putInt(key, value).apply();
}
/**
* SP中读取int
*
* @param key 键
* @return 存在返回对应值,不存在返回默认值-1
*/
public int getInt(@NonNull String key) {
return getInt(key, -1);
}
/**
* SP中读取int
*
* @param key 键
* @param defaultValue 默认值
* @return 存在返回对应值,不存在返回默认值{@code defaultValue}
*/
public int getInt(@NonNull String key, int defaultValue) {
return sp.getInt(key, defaultValue);
}
/**
* SP中写入long
*
* @param key 键
* @param value 值
*/
public void put(@NonNull String key, long value) {
sp.edit().putLong(key, value).apply();
}
/**
* SP中读取long
*
* @param key 键
* @return 存在返回对应值,不存在返回默认值-1
*/
public long getLong(@NonNull String key) {
return getLong(key, -1L);
}
/**
* SP中读取long
*
* @param key 键
* @param defaultValue 默认值
* @return 存在返回对应值,不存在返回默认值{@code defaultValue}
*/
public long getLong(@NonNull String key, long defaultValue) {
return sp.getLong(key, defaultValue);
}
/**
* SP中写入float
*
* @param key 键
* @param value 值
*/
public void put(@NonNull String key, float value) {
sp.edit().putFloat(key, value).apply();
}
/**
* SP中读取float
*
* @param key 键
* @return 存在返回对应值,不存在返回默认值-1
*/
public float getFloat(@NonNull String key) {
return getFloat(key, -1f);
}
/**
* SP中读取float
*
* @param key 键
* @param defaultValue 默认值
* @return 存在返回对应值,不存在返回默认值{@code defaultValue}
*/
public float getFloat(@NonNull String key, float defaultValue) {
return sp.getFloat(key, defaultValue);
}
/**
* SP中写入boolean
*
* @param key 键
* @param value 值
*/
public void put(@NonNull String key, boolean value) {
sp.edit().putBoolean(key, value).apply();
}
/**
* SP中读取boolean
*
* @param key 键
* @return 存在返回对应值,不存在返回默认值{@code false}
*/
public boolean getBoolean(@NonNull String key) {
return getBoolean(key, false);
}
/**
* SP中读取boolean
*
* @param key 键
* @param defaultValue 默认值
* @return 存在返回对应值,不存在返回默认值{@code defaultValue}
*/
public boolean getBoolean(@NonNull String key, boolean defaultValue) {
return sp.getBoolean(key, defaultValue);
}
/**
* SP中写入String集合
*
* @param key 键
* @param values 值
*/
public void put(@NonNull String key, @NonNull Set<String> values) {
sp.edit().putStringSet(key, values).apply();
}
/**
* SP中读取StringSet
*
* @param key 键
* @return 存在返回对应值,不存在返回默认值{@code null}
*/
public Set<String> getStringSet(@NonNull String key) {
return getStringSet(key, Collections.<String>emptySet());
}
/**
* SP中读取StringSet
*
* @param key 键
* @param defaultValue 默认值
* @return 存在返回对应值,不存在返回默认值{@code defaultValue}
*/
public Set<String> getStringSet(@NonNull String key, @NonNull Set<String> defaultValue) {
return sp.getStringSet(key, defaultValue);
}
/**
* SP中获取所有键值对
*
* @return Map对象
*/
public Map<String, ?> getAll() {
return sp.getAll();
}
/**
* SP中移除该key
*
* @param key 键
*/
public void remove(@NonNull String key) {
sp.edit().remove(key).apply();
}
/**
* SP中是否存在该key
*
* @param key 键
* @return {@code true}: 存在<br>{@code false}: 不存在
*/
public boolean contains(@NonNull String key) {
return sp.contains(key);
}
/**
* SP中清除所有数据
*/
public void clear() {
sp.edit().clear().apply();
}
private static boolean isSpace(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;
}
}