Android SharedPreferences 全面解析
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/目錄下創建該文件。
來自:http://www.jianshu.com/p/ad26833a73de