當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > 利用Java反射機(jī)制改變SharedPreferences存儲(chǔ)路徑
利用Java反射機(jī)制改變SharedPreferences存儲(chǔ)路徑
時(shí)間:2018-09-21 來源:未知
近在做一個(gè)項(xiàng)目,想到要使用SharedPreferences類去存儲(chǔ)一些簡單的數(shù)據(jù),但是我們知道,使用SharedPreferences保存數(shù)據(jù),其實(shí)質(zhì)是采用了xml文件存放數(shù)據(jù),路徑為:/data/data/<package name>/shared_prefs. 但是有些時(shí)候,我們不想將xml文件存儲(chǔ)到SharedPreferences累指定的目錄下,比如說,我想將xml文件存儲(chǔ)到sdcard下面,這個(gè)時(shí)候,我們?cè)撛趺崔k呢?
我們知道,SharedPreferences是封裝好的類,我們只能使用類提供的方法,但是我們也知道,使用java的反射機(jī)制,類在我們面前就是透明的,我們可以任意使用類中的方法,變量,構(gòu)造器等等。所以,這里,我想到使用java的反射機(jī)制去解決這個(gè)問題。但是在使用java的反射機(jī)制之前,有些概念我們還是要了解的。
Context類路徑:/frameworks/base/core/java/android/content/Context.java
說明:抽象類,提供了一組通用的API。
源代碼(部分)如下:
public abstract class Context {
...
public abstract Object getSystemService(String name); //獲得系統(tǒng)級(jí)服務(wù)
public abstract void startActivity(Intent intent); //通過一個(gè)Intent啟動(dòng)Activity
public abstract ComponentName startService(Intent service); //啟動(dòng)Service
//根據(jù)文件名得到SharedPreferences對(duì)象
public abstract SharedPreferences getSharedPreferences(String name,int mode);
...
}
ContextIml.java類 路徑 :/frameworks/base/core/java/android/app/ContextImpl.java
說明:該Context類的實(shí)現(xiàn)類為ContextIml,該類實(shí)現(xiàn)了Context類的功能。請(qǐng)注意,該函數(shù)的大部分功能都是直接調(diào)用。
其屬性mPackageInfo去完成。
源代碼(部分)如下:
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context{
//所有Application程序公用一個(gè)mPackageInfo對(duì)象
/*package*/ ActivityThread.PackageInfo mPackageInfo;
@Override
public Object getSystemService(String name){
...
else if (ACTIVITY_SERVICE.equals(name)) {
return getActivityManager();
}
else if (INPUT_METHOD_SERVICE.equals(name)) {
return InputMethodManager.getInstance(this);
}
}
@Override
public void startActivity(Intent intent) {
...
//開始啟動(dòng)一個(gè)Activity
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
}
}
ContextWrapper類 路徑 :\frameworks\base\core\java\android\content\ContextWrapper.java
說明: 正如其名稱一樣,該類只是對(duì)Context類的一種包裝,該類的構(gòu)造函數(shù)包含了一個(gè)真正的Context引用,即ContextIml對(duì)象。源代碼(部分)如下:
public class ContextWrapper extends Context {
Context mBase; //該屬性指向一個(gè)ContextIml實(shí)例,一般在創(chuàng)建Application、Service、Activity時(shí)賦值
//創(chuàng)建Application、Service、Activity,會(huì)調(diào)用該方法給mBase屬性賦值
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent); //調(diào)用mBase實(shí)例方法
}
}
Context相關(guān)類的繼承關(guān)系

SharedPreferences原則上只能保存在當(dāng)前應(yīng)用程序私有的Shared_prefs目錄中,但利用Java的反射機(jī)制可以改變系統(tǒng)內(nèi)定的文件存儲(chǔ)路徑。
例如:將config.xml文件保存在SD卡的根目錄中。
private void savePreToSDcard() {
try {
Field field; // 獲取ContextWrapper對(duì)象中的mBase變量。該變量保存了ContextImpl對(duì)象
field = ContextWrapper.class.getDeclaredField("mBase");
field.setAccessible(true);
// 獲取mBase變量
Object obj = field.get(this);
// 獲取ContextImpl.mPreferencesDir變量,該變量保存了數(shù)據(jù)文件的保存路徑
field = obj.getClass().getDeclaredField("mPreferencesDir");
field.setAccessible(true);
// 創(chuàng)建自定義路徑
File file = new File("/sdcard");
// 修改mPreferencesDir變量的值
field.set(obj, file);
SharedPreferences mySharedPreferences = getSharedPreferences( "config", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = mySharedPreferences.edit();
editor.putString("name", "20130310");
editor.commit();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

