简介
SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态,Activity暂停时,将此activity的状态保存到SharedPereferences中;当Activity重载,系统回调方法onSaveInstanceState时,再从SharedPreferences中将值取出。
原理
SharedPreferences存储数据的本质是在本地新建一个xml文件,以键对值的方式存储数据,文件存放在/data/data/
使用
一个简单的栗子
SharedPreferences sharedPreferences = getSharedPreferences("lizi", Context.MODE_PRIVATE); //新建名为lizi的xml文件
Editor editor = sharedPreferences.edit(); //获取编辑器
editor.putString("name","sharedPreferences"); //写入string数据
editor.putInt("value",10086); //写入int数据
editor.commit(); //提交
方法详解
实例化(单例)
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences sharedPreferences = context.getSharedPreferences("lizi", Context.MODE_PRIVATE);
前者内部也是调用后者来实现的,只不过前者默认新建一个包名+”_preferences”的xml文件 这里我们知道,有关文件读写操作的函数其实都是由contextImpl来实现的,所以真正调用的是contextImpl的函数 参数: context.getSharedPreferences(String name,int mode); name就是需要新建的xml文件的名字,第二个参数为操作模式,共有以下四种
- MODE_APPEND: 追加方式存储
- MODE_PRIVATE: 私有方式存储,其他应用无法访问
- MODE_WORLD_READABLE: 表示当前文件可以被其他应用读取
- MODE_WORLD_WRITEABLE: 表示当前文件可以被其他应用写入
- MODE_MULTI_PROCESS: 适用于多进程访问(3.0以后已经不在支持,google官方推荐使用ContentProvider来实现进程间共享访问)
SharedPreferences内部的操作函数
- Map<String, ?> getAll();
- String getString(String key, @Nullable String defValue);
- Set
getStringSet(String key, @Nullable Set defValues); - int getInt(String key, int defValue);
- long getLong(String key, long defValue)
- float getFloat(String key, float defValue);
- boolean getBoolean(String key, boolean defValue);
- boolean contains(String key); //判断key相对的键对值是否存在
- Editor edit(); //获取Editor对象,所有的写操作都是通过Editor对象进行操作的
- void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener); //注册监听函数
- void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
//注册后必须移除防止内存泄漏
Editor内部的操作函数
- Editor putString(String key, @Nullable String value);
- Editor putStringSet(String key, @Nullable Set
values); - Editor putInt(String key, int value);
- Editor putLong(String key, long value);
- Editor putFloat(String key, float value);
- Editor putBoolean(String key, boolean value);
- Editor remove(String key); //删除key对应的值
- Editor clear(); //移除commit或者apply之前所有操作
- boolean commit(); //提交数据并同步提交到硬盘
- void apply(); //原子性提交内容到内存,等所有提交完成后再提交到硬盘中
- mark! 注意commit和apply的区别:
- commit提交是否成功有返回值而apply没有
- apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘,因此,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率。
- apply方法不会提示任何失败的提示。
特别需要注意的点
以上的操作如果都是在同一个进程进行的,那么不会有什么问题,但是SharedPreferences对文件的读写没有实现AIDL方式,所以在不同的进程中进行操作,取得的对象就会不同,相应的,取得的值也会不同。 举个栗子
<!--声明两个在不同线程中的activity-->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".OtherActivity"
android:process=":other"/>
MainActivity中的代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedPreferences= PreferenceManager.getDefaultSharedPreferences(this);
sharedPreferences.edit().putInt("key",10086).commit();
}
public void change(View view){
SharedPreferences sharedPreferences= PreferenceManager.getDefaultSharedPreferences(this);
sharedPreferences.edit().putInt("key",66666).commit();
Log.i("mainActivity",sharedPreferences.getInt("key",-1)+"");
}
public void startOther(View view){
Intent intent=new Intent(this,OtherActivity.class);
startActivity(intent);
}
}
OtherActivity中的代码
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
}
public void getText(View view){
SharedPreferences sharedPreferences= PreferenceManager.getDefaultSharedPreferences(this);
Log.i("otherActivity",sharedPreferences.getInt("key",-1)+"");
}
原理很简单,在mainactivity中首先通过SharedPreferences写入一个值10086 启动otherActivity来读取这个值并打印 在回到mainActivity中修改这个值,在otherActivity中获取这个值并打印 other中第一次获取的值
05-09 16:10:58.986 16994-16994/com.spring.sptest:other I/otherActivity: 10086
回到mainActivity中改变里面的值后otherActivity再次获取值
05-09 16:12:28.629 16098-16098/com.spring.sptest I/mainActivity: 66666
05-09 16:12:31.548 16994-16994/com.spring.sptest:other I/otherActivity: 10086
可以看到,otherActivity中的值并没有做相应的改变
由此我们可以得出结论:
SharedPreferences对值的操作并非进程同步的
原因就是因为不同进程会分别对SharedPreferences做缓存操作以避免复杂的io操作,整个SharedPreferences的获取流程大概如下
if(缓存中存在相应的SharedPreferences&&mode==MODE_MULTI_PROCESS&&version<Android3.0){
直接返回SharedPreferences对象
}else{
从硬盘中读取xml文件并返回SharedPreferences对象
}
由此可以分析上述代码,由于在内存中已经做了缓存造作,所以otherActivity所在的进程直接返回了缓存中的SharedPreferences对象,导致了读取的值没有改变。解决办法,重启进程重新从硬盘读取xml文件