Android应用Preference相关及源码浅析(SharePreferences篇)

本文详细分析了Android中的SharedPreferences实现,包括SharePreferencesImpl类的构造、数据加载、编辑器EditorImpl的工作原理,以及commit和apply方法的实现。通过源码揭示了SharedPreferences在内存与磁盘间的操作流程,强调了数据同步和异步操作的重要性,以及在性能和内存使用上的考量。
摘要由CSDN通过智能技术生成

boolean contains(String key);

//针对preferences创建一个新的Editor对象,通过它你可以修改preferences里的数据,并且原子化的将这些数据提交回SharedPreferences对象

Editor edit();

//注册一个回调函数,当一个preference发生变化时调用

void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);

//注销一个之前(注册)的回调函数

void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);

}

很明显的可以看见,SharePreference源码其实是很简单的。既然这里说了SharePreference类只是一个接口,那么他一定有自己的实现类的,怎么办呢?我们继续往下看。

3-2 SharePreferences实现类SharePreferencesImpl分析

我们从上面SharePreference的使用入口可以分析,具体可以知道SharePreference的实例获取可以通过两种方式获取,一种是Activity的getPreferences方法,一种是Context的getSharedPreferences方法。所以我们如下先来看下这两个方法的源码。

先来看下Activity的getPreferences方法源码,如下:

public SharedPreferences getPreferences(int mode) {

return getSharedPreferences(getLocalClassName(), mode);

}

哎?可以发现,其实Activity的SharePreference实例获取方法只是对Context的getSharedPreferences再一次封装而已,使用getPreferences方法获取实例默认生成的xml文件名字是当前activity类名而已。既然这样那我们还是转战Context(其实现在ContextImpl中,至于不清楚Context与ContextImpl及Activity关系的请先看这篇博文,点我迅速脑补)的getSharedPreferences方法,具体如下:

//ContextImpl类中的静态Map声明,全局的一个sSharedPrefs

private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;

//获取SharedPreferences实例对象

public SharedPreferences getSharedPreferences(String name, int mode) {

//SharedPreferences的实现类对象引用声明

SharedPreferencesImpl sp;

//通过ContextImpl保证同步操作

synchronized (ContextImpl.class) {

if (sSharedPrefs == null) {

//实例化对象为一个复合Map,key-package,value-map

sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();

}

//获取当前应用包名

final String packageName = getPackageName();

//通过包名找到与之关联的prefs集合packagePrefs

ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);

//懒汉模式实例化

if (packagePrefs == null) {

//如果没找到就new一个包的prefs,其实就是一个文件名对应一个SharedPreferencesImpl,可以有多个对应,所以用map

packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();

//以包名为key,实例化的所有文件map作为value添加到sSharedPrefs

sSharedPrefs.put(packageName, packagePrefs);

}

if (mPackageInfo.getApplicationInfo().targetSdkVersion <

Build.VERSION_CODES.KITKAT) {

if (name == null) {

//nice处理,name传null时用"null"代替

name = “null”;

}

}

//找出与文件名name关联的sp对象

sp = packagePrefs.get(name);

if (sp == null) {

//如果没找到则先根据name构建一个File的prefsFile对象

File prefsFile = getSharedPrefsFile(name);

//依据上面的File对象创建一个SharedPreferencesImpl对象的实例

sp = new SharedPreferencesImpl(prefsFile, mode);

//以key-value方式添加到packagePrefs中

packagePrefs.put(name, sp);

返回与name相关的SharedPreferencesImpl对象

return sp;

}

}

//如果不是第一次,则在3.0之前(默认具备该mode)或者mode为MULTI_PROCESS时调用reload方法

if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||

getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {

//重新加载文件数据

sp.startReloadIfChangedUnexpectedly();

}

//返回SharedPreferences实例对象sp

return sp;

}

我们可以发现,上面方法中首先调运了getSharedPrefsFile来获取一个File对象,所以我们继续先来看下这个方法,具体如下:

public File getSharedPrefsFile(String name) {

//依据我们传入的文件名字符串创建一个后缀为xml的文件

return makeFilename(getPreferencesDir(), name + “.xml”);

}

private File getPreferencesDir() {

synchronized (mSync) {

if (mPreferencesDir == null) {

//获取当前app的data目录下的shared_prefs目录

mPreferencesDir = new File(getDataDirFile(), “shared_prefs”);

}

return mPreferencesDir;

}

}

可以看见,原来SharePreference文件存储路径和文件创建是这个来的。继续往下看可以发现接着调运了SharedPreferencesImpl的构造函数,至于这个构造函数用来干嘛,下面会分析。

好了,到这里我们先回过头稍微总结一下目前的源码分析结论,具体如下:

前面我们有文章分析了Android中的Context,这里又发现ContextImpl中有一个静态的ArrayMap变量sSharedPrefs。这时候你想到了啥呢?无论有多少个ContextImpl对象实例,系统都共享这一个sSharedPrefs的Map,应用启动以后首次使用SharePreference时创建,系统结束时才可能会被垃圾回收器回收,所以如果我们一个App中频繁的使用不同文件名的SharedPreferences很多时这个Map就会很大,也即会占用移动设备宝贵的内存空间,所以说我们应用中应该尽可能少的使用不同文件名的SharedPreferences,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值