Android SharedPreferences★★★★

1.SharedPreferences

在Android中,通常需要存储一些数据,一些大型的数据如图片、JSON数据等,可以通过读写File的方式实现;一些大量级的关系型数据,可以通过数据库SQLite实现;而一些简单的、无安全风险的键值对数据,可以通过Android提供的SharedPreferences实现。

SharedPreferences是一个轻量级的存储类,特别适合用于保存软件配置参数。其背后是用xml文件存放数据,文件存放在/data/data//shared_prefs目录下。SharedPreferences所保存的数据会一直存在,除非被覆盖、移除、清空或文件被删除。(SharedPreferences保存的数据会随着应用的卸载而被删除)

SharedPreferences可以保存的数据类型有:int、boolean、float、long、String、StringSet。

SharedPreferences优点:

相对于文件存储来说比较方便,支持多种数据类型的存储。

SharedPreferences缺点:

①不安全,一般只用来存储配置信息

②对数据的操作单一

③存储相同的key值时,存入的数据会被覆盖

 

2.SharedPreferences使用

①获取到应用中的SharedPreferences

有三种方式。

1)getSharedPreferences(String,mode)

如果需要多个通过名称参数来区分的sharedpreference文件, 名称可以通过第一个参数来指定。可在app中通过任何一个Context 执行该方法。

SharedPreferences sp = context.getSharedPreferences("setting", Context.MODE_PRIVATE);

第一次访问名为"setting"的SharedPreferences文件时,系统会在应用数据目录下(/data/data/packageName/)的shared_prefs文件夹下,创建一个同名的xml文件。也就是说该文件不存在时,直接创建;如果已经存在,则直接使用。

mode指定为MODE_PRIVATE,则该配置文件只能被自己的应用程序访问。

2)getPreferences(mode)

这个方法默认使用当前类不带包名的类名作为文件的名称,配置文件仅可以被调用的Activity使用。当Activity只需要创建一个SharedPreferences对象的时候,可以使用该方法。

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);

3)PreferenceManager.getDefaultSharedPreferences(Context)

每个应用都有一个默认的配置文件preferences.xml,可以使用getDefaultSharedPreferences获取。

每个应用默认的配置文件的名字是:包名+_preferences,其文件读取类型为Context.MODE_PRIVATE。

看一下它的源码:

public static SharedPreferences getDefaultSharedPreferences(Context context) {

    return context.getSharedPreferences( getDefaultSharedPreferencesName(context),getDefaultSharedPreferencesMode());

}

 private static String getDefaultSharedPreferencesName(Context context) {

    return context.getPackageName() + "_preferences";

}

private static int getDefaultSharedPreferencesMode() {

    return Context.MODE_PRIVATE;

}

以上三种获取SharedPreferences的方法都提到了mode,来看一下关于mode的指定:

1)私有模式​ Context.MODE_PRIVATE

​ 只能被创建这个文件的当前应用访问。若文件不存在会创建文件;若创建的文件已存在则会覆盖掉原来的文件。

2)追加模式​ Context.MODE_APPEND

​ 只能被创建这个文件的当前应用访问。若文件不存在会创建文件;若文件存在则在文件的末尾进行追加内容。

3)可读模式​ Context.MODE_WORLD_READABLE

​ 创建出来的文件可以被其他应用所读取

4)可写模式​ Context.MODE_WORLD_WRITEABLE

​ 允许其他应用对其进行写入。

②读写SharedPreferences

1)写SharedPreferences

为了写sharedPreferences文件,需要通过执行edit()创建一个 SharedPreferences.Editor。通过putXXX()方法传递keys与values,最后通过commit() 或apply()提交改变。

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);

SharedPreferences.Editor editor = sharedPref.edit();

editor.putString("number",number);

editor.putString("password",pwd);

editor.apply(); 或 editor.commit();

commit表示同步提交到SharedPreferences文件,获取是否同步成功的结果:boolean success = editor.commit();

apply表示异步提交到SharedPreferences文件:editor.apply();

2)读SharedPreferences

通过getXXX()方法从sharedPreferences中读取数据。在这些方法里面传入想要获取的value对应的key,并提供一个默认的value作为查找的key不存在时函数的返回值。如下:

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);

String number=sp.getString("number","");

String pasword=sp.getString("password","");

③移除数据

1)移除指定key的数据(由Editor对象调用)

abstract SharedPreferences.Editor remove(String key)

参数key:指定数据的key

2)清空数据(由Editor对象调用)

abstract SharedPreferences.Editor clear()

④系统默认的SharedPreferences

每个应用都有一个默认编好的preferences.xml文件,使用getDefaultSharedPreferences获取,其余操作是一样的。

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

SharedPreferences.Editor editor = preferences.edit();

editor.putBoolean("if_set_location", false);

editor.commit();

⑤访问其他应用的SharedPreferences

如果应用B要读写访问A应用中的Preference前提条件是,A应用中该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限,代表其他的应用能访问读取或者写入。

具体步骤:

在B中创建一个指向A应用的Context:

Context otherAppsContext = createPackageContext("A应用的包名", Context.CONTEXT_IGNORE_SECURITY);

然后通过context获取到SharedPreferences实体:

SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences("SharedPreferences的文件名", Context.MODE_WORLD_READABLE);

String name = sharedPreferences.getString("key", "");

注:如果不通过创建Context访问其他应用的preference,也可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如:

File xmlFile = new File(“/data/data/<package name>/shared_prefs/itcast.xml”);

//<package name>应替换成应用的包名。

 

3.SharedPreferences变化监听

这是当SharedPreferences改变时的回调,是SharedPreferences的一个接口。

通过registerOnSharedpreferenceListener方法设置监听:

SharedPreferences sp = getSharedPreferences( "testSP", Context.MODE_PRIVATE);

sp. registerOnSharedPreferenceChangeListener( new SharedPreferences. OnSharedPreferenceChangeListener() {

    @Override

    public void onSharedPreferenceChanged( SharedPreferences sharedPreferences, String s) {

        Log.i("spTest","sp changed, key is "+ s);

    }

});

关于这个监听,官方文档是这样描述的:

Called when a shared preference is changed, added, or removed.

This may be called even if a preference is set to its existing value.

This callback will be run on your main thread.

使用这个监听时,如果你用匿名对象也就是下面这样,可能会被当作垃圾回收,导致会回调一次你的callback,达不到监听的效果。

//匿名回调

protected void onCreate(Bundle savedInstanceState)  {   

    SharedPreferences sp = getSharedPreferences( "testSP", Context.MODE_PRIVATE);

     sp.registerOnSharedPreferenceChangeListe ner(new OnSharedPreferenceChangeListener() {

        @Override

        public void onSharedPreferenceChanged( SharedPreferences sharedPreferences, String key) {

            Log.i(LOGTAG, "testOnSharedPreference ChangedWrong key =" + key);

        }

    });

这种写法看上去没有什么问题,而且很多时候开始几次onSharedPreferenceChanged方法也可以被调用。但是过一段时间(简单demo 不容易出现,但是使用DDMS中的gc会立刻导致接下来的问题),你会发现前面的方法突然不再被调用,进而影响到程序的处理。

原因剖析:

真正的原因就是注册的监听器被移除掉了。

首先先了解一下registerOnSharedPreferenceChangeListener注册的实现。

private final WeakHashMap<OnSharedPreferenc eChangeListener, Object> mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();

registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {

    synchronized(this) {

        mListeners.put(listener, mContent);

    }

从上面的代码可以得知,一个OnSharedPreferenceChangeListener对象实际上是放到了一个WeakHashMap的容器中,执行完示例中的onCreate方法,这个监听器对象很快就会成为垃圾回收的目标,由于放在WeakHashMap中作为key不会阻止垃圾回收, 所以当监听器对象被回收之后,这个监听器也会从mListeners中移除。所以就造成了onSharedPreferenceChanged不会被调用。

解决办法:改为对象成员变量(推荐)

将监听器作为Activity的一个成员变量,在Activity的onResume进行注册,在onPause时进行注销。推荐在这两个Activity生命周期中进行处理,尤其是当SharedPreference值发生变化后,对Activity展示的UI进行处理操作的情况。这种方法是最推荐的解决方案。

private OnSharedPreferenceChangeListener mListener = new OnSharedPreferenceChangeL istener() {

    @Override

    public void onSharedPreferenceChanged( SharedPreferences sharedPreferences, String key) {

        Log.i(LOGTAG, "instance variable key=" + key);

    }

};

@Override

protected void onResume() {

 sp.registerOnSharedPreferenceChangeListener(mListener);

    super.onResume();

}

@Override

protected void onPause() {   

    sp.unregisterOnSharedPreferenceChangeList ener(mListener);

    super.onPause();

}

总结一下:

①仅当添加或更改值时,监听器才会触发,设置相同的值将不会调用它;

②监听器需要保存在成员变量中,而不是匿名类,因为registerOnSharedPreferenceChangeListener使用弱引用进行存储,因此将被垃圾回收;

③除了使用成员变量,也可以由类直接实现,然后调用 registerOnSharedPreferenceChangeListener(this);

④当不再需要使用时࿰

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值