Android(安卓)数据存储:SharedPreferences(SP)
作为 Android 的数据存储方式之一的 SharedPreferences(以下简称SP),我们在开发中也是或多或少会用到。今天就来总结一下如何使用 SP 以及使用 SP 的注意事项。
1.首先先聊聊使用 SP 的注意事项
- SP 适合存储一些轻量级的持久化数据,如果你的数据量很大,那么建议你更换存储方式。
- SP 提供了数据的一致性,但这是以牺牲程序性能为代价的,所以如果存储的数据需要经常修改,那么建议你更换存储方式。
- SP 是不支持多进程读写的,如果你需要多进程对数据进行读写访问,那么建议你更换存储方式。
- SP 的 commit 方法是同步进行的,apply 是异步进行的,两者都是以替换上次数据来进行数据更新的,如果同时有两个地方调用 commit 或者 apply ,以最后一次调用为最终数据更新。
- 如果你不关心 SP 的操作返回值,同时你还是在 Android 主线程进行操作,那么建议你使用 apply 方法进行数据更新。
- 因为 SP 的 apply 方法会异步进行数据更新,那么在 apply 方法尚未完成的时候,调用 commit 方法进行数据更新,就会使 commit 方法进行阻塞,直到 apply 方法完成所有的异步数据更新。
2. 好的,接下来我们就来看看 SP 的具体使用
- SP 使应用程序共享它的同一个实例,通过 XML 以 key-value 的形式保存数据。
- SP 主要用来保存一些轻量级的数据(字符串、基本数据类型),比如应用程序的各种配置信息,以及一些简单的账号、密码等。
- SP 的数据文件储存位置:data/data/应用程序包名/shared_prefs/
- SP 的数据访问模式
MODE_PRIVATR | 默认模式,创建保存的文件只能本应用程序或者拥有相同用户ID的应用程序访问 |
MODE_WORLD_READABLE | 允许所有应用程序对创建的文件进行读操作权限(官方不建议使用,数据不安全) |
MODE_WORLD_WRITEABLE | 允许所有应用程序对创建的文件进行写操作权限(官方不建议使用,数据不安全) |
- SP的方法
adstract boolean | contains(String key) 检查SP文件是否包含此 key。 |
adstract SharedPreferences.Editor | edit() 创建一个SP文件编辑器,通过这个编辑器可以编辑SP里面的内容,并将这些修改提交给SP。 |
adstract Map | getAll() 从SP中查询出所有的 key-value。 |
adstract boolean | getBoolean(String key,boolean defValue) 根据 key 从 SP 中查询对应的 boolean 值,如果查不到就返回默认值。 |
adstract float | getFloat(String key,float defValue) 根据 key 从 SP 中查询对应的 float 值,如果查不到就返回默认值。 |
adstract int | getInt(String key,int defValue) 根据 key 从 SP 中查询对应的 int 值,如果查不到就返回默认值。 |
adstract long | getLong(String key,long defValue) 根据 key 从 SP 中查询对应的 long 值,如果查不到就返回默认值。 |
adstract String | getString(String key,String defValue) 根据 key 从 SP 中查询对应的 String 值,如果查不到就返回默认值。 |
adstract Set | getStringSet(String key,Set 根据 key 从 SP 中查询对应的一组 String 值,如果查不到就返回默认值。 |
adstract void | registerOnSharedPreferencesChangeListener(SharedPreferences.OnSharedPreferencesChangeListener listener ) 注册SP发生改变的监听回调 |
adstract void | unregisterOnSharedPreferencesChangeListener(SharedPreferences.OnSharedPreferencesChangeListener listener ) 取消SP发生改变的监听回调 |
- SharedPreferences.Editor 接口的方法
adstract void | apply() 将SP的修改返回给当前正在被编辑的SP。(异步提交,不保证数据完整性,如果你在apply() 未完成前调用commit(),则会造成commit()阻塞,直到apply()执行完成,才会执行commit(),如果你不在乎返回值的话,可以将 commit() 替换成 apply()。) |
adstract SharedPreferences.Editor | clear() 清空SP中的所有数据。 |
adstract boolean | commit() 将SP的修改返回给当前正在被编辑的SP。(同步提交) 如果您不关心返回值并且正在从应用程序的主线程中使用它,请考虑使用apply()。 |
adstract SharedPreferences.Editor | PutBoolean(String key,boolean value) 在SP编辑器中设置一个布尔值,一旦调用commit()或apply(),就会被写入。 |
adstract SharedPreferences.Editor | PutFloat(String key,float value) 在SP编辑器中设置一个float值,一旦调用commit()或apply(),就会被写入。 |
adstract SharedPreferences.Editor | PutInt(String key,int value) 在SP编辑器中设置一个int值,一旦调用commit()或apply(),就会被写入。 |
adstract SharedPreferences.Editor | PutLong(String key,long value) 在SP编辑器中设置一个long值,一旦调用commit()或apply(),就会被写入。 |
adstract SharedPreferences.Editor | PutString(String key,String value) 在SP编辑器中设置一个String值,一旦调用commit()或apply(),就会被写入。 |
adstract SharedPreferences.Editor | PutStringSet(String key,Set 在SP编辑器中设置一组String值,一旦调用commit()或apply(),就会被写入。 |
adstract SharedPreferences.Editor | remove(String key) 根据key,删除SP中的值。 |
至此SP的功能已经介绍完了。
我们接下来就看看具体的用法以及自己实现一个SPUtils。
- 我们先动手封装一个SPUtils,这样大大减少了很多的模板代码,你也可以根据自己的业务自定义封装,以下是我封装的。
import android.content.Context;import android.content.SharedPreferences;import java.util.Map;public class SPUtils { private final static String spName = "Test"; public static void putValue(Context context, String key, Object value) { SharedPreferences sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE); SharedPreferences.Editor edit = sp.edit(); if (value instanceof Boolean) { edit.putBoolean(key, (Boolean) value); } else if (value instanceof Float) { edit.putFloat(key, (Float) value); } else if (value instanceof Integer) { edit.putInt(key, (Integer) value); } else if (value instanceof Long) { edit.putLong(key, (Long) value); } else if (value instanceof String) { edit.putString(key, (String) value); } edit.apply(); } public static Object getValue(Context context, String key, Object defValue) { SharedPreferences sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE); if (defValue instanceof Boolean) { return sp.getBoolean(key, (Boolean) defValue); } else if (defValue instanceof Float) { return sp.getFloat(key, (Float) defValue); } else if (defValue instanceof Integer) { return sp.getInt(key, (Integer) defValue); } else if (defValue instanceof Long) { return sp.getLong(key, (Long) defValue); } else if (defValue instanceof String) { return sp.getString(key, (String) defValue); } return null; } public static void clearSP(Context context) { context.getSharedPreferences(spName, Context.MODE_PRIVATE) .edit() .clear() .apply(); } public static void removeSP(Context context, String Key) { context.getSharedPreferences(spName, Context.MODE_PRIVATE) .edit() .remove(Key) .apply(); } public static Map getAllSP(Context context) { return context.getSharedPreferences(spName, Context.MODE_PRIVATE).getAll(); }}
- 我们现在模拟登录页面保存账号密码的功能。我创建了两个button,一个用来存储账号密码,一个用来读取账号密码并且进行删除和清空操作。具体如下:
public class MainActivity extends AppCompatActivity { public static final String SP_USERNAME_KEY = "SP_USERNAME_KEY"; public static final String SP_PASSWORD_KEY = "SP_PASSWORD_KEY"; public static final String TAG = "Main_Activity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btn_put).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SPUtils.putValue(MainActivity.this, SP_USERNAME_KEY, "哈哈"); SPUtils.putValue(MainActivity.this, SP_PASSWORD_KEY, 123456); } }); findViewById(R.id.btn_get).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //1.首次正常获取 Map allSP = SPUtils.getAllSP(MainActivity.this); int size = allSP.size(); Log.d(TAG, "1.getAllSP.size() --> " + size); String username = (String) SPUtils.getValue(MainActivity.this, SP_USERNAME_KEY, ""); int password = (int) SPUtils.getValue(MainActivity.this, SP_PASSWORD_KEY, -1); Log.d(TAG, "1.username --> " + username + " ,1.password --> " + password); //2.删除 SP_USERNAME_KEY 后,打印sp数量,以及数据情况 SPUtils.removeSP(MainActivity.this, SP_USERNAME_KEY); Map allSP2 = SPUtils.getAllSP(MainActivity.this); int size2 = allSP2.size(); Log.d(TAG, "2.getAllSP.size() --> " + size2); String username2 = (String) SPUtils.getValue(MainActivity.this, SP_USERNAME_KEY, ""); int password2 = (int) SPUtils.getValue(MainActivity.this, SP_PASSWORD_KEY, -1); Log.d(TAG, "2.username --> " + username2 + " ,2.password --> " + password2); //清空sp后,打印sp数量,以及数据情况 SPUtils.clearSP(MainActivity.this); Map allSP3 = SPUtils.getAllSP(MainActivity.this); int size3 = allSP3.size(); Log.d(TAG, "3.getAllSP.size() --> " + size3); String username3 = (String) SPUtils.getValue(MainActivity.this, SP_USERNAME_KEY, ""); int password3 = (int) SPUtils.getValue(MainActivity.this, SP_PASSWORD_KEY, -1); Log.d(TAG, "3.username --> " + username3 + " ,3.password --> " + password3); } }); }}
- 此为Log输出信息:
D/Main_Activity: 1.getAllSP.size() --> 2D/Main_Activity: 1.username --> 哈哈 ,1.password --> 123456D/Main_Activity: 2.getAllSP.size() --> 1D/Main_Activity: 2.username --> ,2.password --> 123456D/Main_Activity: 3.getAllSP.size() --> 0D/Main_Activity: 3.username --> ,3.password --> -1
至此SP的介绍以及使用就完毕了,希望对你有帮助。
欢迎加入Q群一起探讨Android问题。
更多相关文章
- Android(安卓)APP连接电脑数据库(以SQL Server为例)
- 9个非常棒的Android代码编辑器 移动开发者的最爱
- Android(安卓)Studio Jni开发(二)实现Native调用java方法和Native
- android SQLite数据库1
- 初学android-调用百度api显示地图(出现显示网格问题)
- Android(安卓)小型社交软件客户端开发技术栈+案例
- Android音频系统之AudioTrack起播线与underrun问题研究(Android(
- Android(安卓)RecyclerView中ViewHolder的复用导致数据错乱解决
- Android数据传输加密(一):Base64转码算法