SharedPreference是以key-value键值对的形式存储数据,它只能存储简单的基本数据类型:boolean, float, int, long, String. 它的文件是在data/data/package-name/shared-prefs/目录下。
获取SharedPreferences对象
可以使用以下两种方法之一:
getSharedPreferences(String name, int mode)
getPreferences(int mode)
其实getPreferences()
内部也是调用了getSharedPreferences()
,看下源码:
public SharedPreferences getPreferences(int mode) {
return getSharedPreferences(getLocalClassName(), mode);
}
/**
* Returns class name for this activity with the package prefix removed.
* This is the default name used to read and write settings.
*
* @return The local class name.
*/
@NonNull
public String getLocalClassName() {
final String pkg = getPackageName();
final String cls = mComponent.getClassName();
int packageLen = pkg.length();
if (!cls.startsWith(pkg) || cls.length() <= packageLen
|| cls.charAt(packageLen) != '.') {
return cls;
}
return cls.substring(packageLen+1);
}
getPreferences()
是Activity的方法,不需要传入name
参数,它返回的是以getLocalClassName()
返回值命名的SharedPreferences对象,而getLocalClassName()
方法返回的是去掉package-name的当前Activity类名。所以在不同的Activity中调用getPreferences()
返回的是不同的SharedPreferences对象。
例如:
package com.lc.learndemo.sharedpreference;
...
import com.lc.learndemo.R;
public class SharedPrefsActivity extends Activity implements View.OnClickListener{
private SharedPreferences sPrefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shared_prefs);
sPrefs = getPreferences(MODE_PRIVATE);//此时并没有创建文件
sPrefs.edit().putString("name","小明").commit();//第一次写数据的时候才会创建文件
}
}
启动这个Activity后,会在data/data/package-name/shared-prefs/目录下创建一个名为sharedpreference.SharedPrefsActivity
的xml文件。
SharedPreferences的读写
SharedPreferences本身只支持读数据:
SharedPreferences sPrefs = getSharedPreferences("config_sprefs", MODE_PRIVATE);
String name = sPrefs.getString("name","该值不存在")
而存储或修改数据则需要通过SharedPreferences.Editor
对象。例如:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shared_prefs);
SharedPreferences sPrefs = getSharedPreferences("config_sprefs", MODE_PRIVATE);
SharedPreferences.Editor editor = sPrefs.edit(); //获取Editor对象
editor.putString("name","小明"); //存储数据
editor.commit(); //提交修改
}
SharedPreferences的标志位
文件创建标志位:
- Context.MODE_PRIVATE 这是默认标志位,表示创建的文件只能被当前应用访问。
- Context.MODE_WORLD_READABLE 允许其它应用程序读该文件。
- Context.MODE_WORLD_WRITEABLE 允许其它应用程序写该文件。
文件加载标志位:
- Context.MODE_MULTI_PROCESS 这是文件加载标志位,表示即使你的SharedPreferences文件已经加载到进程,系统还是会去检查文件是否更改。这个是在API level 11加入的,解决的问题是:当加载SharedPreference文件的时候,系统会在内存中留有一份缓存,所以当SharedPreference文件的内容发生改变时,其他应用程序读取的还是缓存的数据,不能读到最新的数据,当设置这个标志位问题就解决了。这个标志主要用在跨进程访问中。
跨进程访问SharedPreferences
同一个应用中的跨进程访问
首先创建应用App1,创建A
Activity,在A中创建SharedPreferences
public class A extends Activity implements View.OnClickListener {
private SharedPreferences sPrefs;
private SharedPreferences.Editor editor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shared_prefs);
sPrefs = getSharedPreferences("config_sprefs",MODE_WORLD_READABLE);
editor = sPrefs.edit();
editor.putString("name","小明");
editor.commit();
init();
}
private void init () {
Button editButton = (Button) findViewById(R.id.btn_edit);
editButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_edit:
editor.putString("name","张三").commit();
}
}
}
在应用App1中再创建B
Activity,在AndroidManifest.xml中给B Activity 指定在另一个独立的进程中运行:
<activity android:name=".B"
android:process=":Remote" />
在B中跨进程访问App1所在的进程的SharedPreference文件:
public class B extends Activity implements View.OnClickListener{
private TextView tvAcrossProcess;
private Button btnAcrossProcess;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_androidprocess);
initViews();
}
private void initViews () {
tvAcrossProcess = (TextView) findViewById(R.id.tv_across_process);
btnAcrossProcess = (Button) findViewById(R.id.btn_across_process);
btnAcrossProcess.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_across_process:
/*在同一个应用中得进程可以直接获取SharedPreferences对象,加载模式设置为MODE_MULTI_PROCESS才可以对到修改后的数据*/
SharedPreferences sp = getSharedPreferences("config_sprefs", MODE_MULTI_PROCESS);
tvAcrossProcess.setText(sp.getString("name","该值不存在"));
}
}
}
B中有一个Button和一个TextView,点击Button跨进程访问SharedPreferences,获取的内容显示到TextView中。
不同应用程序之间的跨进程访问
我们再创建一个App2,在App2中创建C
Activity,点击Button访问App1中得SharedPreferences,结果显示在TextView中:
public class C extends Activity implements View.OnClickListener{
private TextView tvAcrossProcess;
private Button btnAcrossProcess;
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews () {
tvAcrossProcess = (TextView) findViewById(R.id.tv_across_process);
btnAcrossProcess = (Button) findViewById(R.id.btn_across_process);
btnAcrossProcess.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_across_process:
try {
context = createPackageContext("com.lc.learndemo",CONTEXT_IGNORE_SECURITY);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
SharedPreferences sp = context.getSharedPreferences("config_sprefs", MODE_MULTI_PROCESS);
String content = sp.getString("name","该值不存在");
tvAcrossProcess.setText(content);
}
}
}
createPackageContext(String packageName, int flags)
创建其它程序的Context,第一个参数是应用的包名,第二个参数是标志位,它有两个值,CONTEXT_INCLUDE_CODE的意思是包括代码,也就是说可以执行这个包里面的代码。CONTEXT_IGNORE_SECURITY的意思 是忽略安全警告,如果不加这个标志的话,有些功能是用不了的,会出现安全警告。
但是谷歌官方文档不建议使用SharedPreferences来进行跨进程通信,会有安全性问题,可以用ContentProvider, BroadcastReceiver, 或Service来代替.
SharedPreferences.OnSharedPreferenceChangeListener
这个接口用来监听SharedPreferences内容变化的,其内部有两个方法:
//注册监听
registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)
//解除注册
unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)
注意:当调用getXxx()
方法获取SharedPreference对象是,这个文件并没有创建,只有当第一次调用putXxx()
方法想文件中写值得时候才会在data/data/package-name/shared-prefs/目录下创建该文件。