讲师博文
利用Java反射机制改变SharedPreferences存储路径 来源 : 未知     2018-09-21

近在做一个项目,想到要使用SharedPreferences类去存储一些简单的数据,但是我们知道,使用SharedPreferences保存数据,其实质是采用了xml文件存放数据,路径为:/data/data/<package name>/shared_prefs. 但是有些时候,我们不想将xml文件存储到SharedPreferences累指定的目录下,比如说,我想将xml文件存储到sdcard下面,这个时候,我们该怎么办呢?

我们知道,SharedPreferences是封装好的类,我们只能使用类提供的方法,但是我们也知道,使用java的反射机制,类在我们面前就是透明的,我们可以任意使用类中的方法,变量,构造器等等。所以,这里,我想到使用java的反射机制去解决这个问题。但是在使用java的反射机制之前,有些概念我们还是要了解的。

Context类路径:/frameworks/base/core/java/android/content/Context.java

说明:抽象类,提供了一组通用的API。

源代码(部分)如下:

public abstract class Context {

...

public abstract Object getSystemService(String name); //获得系统级服务

public abstract void startActivity(Intent intent); //通过一个Intent启动Activity

public abstract ComponentName startService(Intent service); //启动Service

//根据文件名得到SharedPreferences对象

public abstract SharedPreferences getSharedPreferences(String name,int mode);

...

}

ContextIml.java类 路径 :/frameworks/base/core/java/android/app/ContextImpl.java

说明:该Context类的实现类为ContextIml,该类实现了Context类的功能。请注意,该函数的大部分功能都是直接调用。

其属性mPackageInfo去完成。

源代码(部分)如下:

/**

* Common implementation of Context API, which provides the base

* context object for Activity and other application components.

*/

class ContextImpl extends Context{

//所有Application程序公用一个mPackageInfo对象

/*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) {

...

//开始启动一个Activity

mMainThread.getInstrumentation().execStartActivity(

getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);

}

}

ContextWrapper类 路径 :\frameworks\base\core\java\android\content\ContextWrapper.java

说明: 正如其名称一样,该类只是对Context类的一种包装,该类的构造函数包含了一个真正的Context引用,即ContextIml对象。源代码(部分)如下:

public class ContextWrapper extends Context {

Context mBase; //该属性指向一个ContextIml实例,一般在创建Application、Service、Activity时赋值

//创建Application、Service、Activity,会调用该方法给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); //调用mBase实例方法

}

}

Context相关类的继承关系

利用Java反射机制改变SharedPreferences存储路径

SharedPreferences原则上只能保存在当前应用程序私有的Shared_prefs目录中,但利用Java的反射机制可以改变系统内定的文件存储路径。

例如:将config.xml文件保存在SD卡的根目录中。

private void savePreToSDcard() {

try {

Field field; // 获取ContextWrapper对象中的mBase变量。该变量保存了ContextImpl对象

field = ContextWrapper.class.getDeclaredField("mBase");

field.setAccessible(true);

// 获取mBase变量

Object obj = field.get(this);

// 获取ContextImpl.mPreferencesDir变量,该变量保存了数据文件的保存路径

field = obj.getClass().getDeclaredField("mPreferencesDir");

field.setAccessible(true);

// 创建自定义路径

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();

}

}

扫码申领本地嵌入式教学实录全套视频及配套源码

上一篇:Coretex_M0工程创建

下一篇:安卓中实现蓝牙通信的工具

400-611-6270

Copyright © 2004-2024 华清远见教育科技集团 版权所有
京ICP备16055225号-5京公海网安备11010802025203号