SharedPreferences 详解
2015-10-23 11:52
330 查看
文章出处:http://blog.csdn.net/shift_wwx
请转载的朋友标明出处~~
前言:之前 SharedPreference 实现不同进程间的数据共享 中谈了一下数据共享,最近在用到这一块的时候感觉有点模糊,索性就看一下source code,分享一下~
一、使用
分两个函数:
二、source code 详解
1、获取对象
code 中拖过getSharePreferences 来获取SharedPreferences 的对象,调用过程不说了,说一下实现:
1)一个package 可以创建多个xml,每个xml代表一个SharedPreferences 对象
2)如果xml 没有的时候会新建文件,新建一个SharedPreferences 对象
3)参数mode是 Context.MODE_MULTI_PROCESS 的时候,可以允许多进程操作
4)SharedPreferences 真正实现的class 是SharedPreferencesImpl
2、读取信息
SharedPreferences 从source code看,是一个interface:
几个get 的方法:
3、存储数据
使用的时候SharedPreferences 用内部类Editor,可是Source code 中Editor 也是interface ,实现的地方是EditorImpl
几个put 的接口:
4、Editor 其他的一些接口
1)clear
刚开始看到这个很奇怪,功能是remove的,为什么会put呢,因为是两份map操作,这个临时的map,即mModified不知道mMap 里面有没有这个,所以,就put 了this。
在commit的时候会比较每个元素,当碰到了this 之后会确认mMap 里面是否存在,没有就算了,有就remove掉:
if (v == this || v == null) {
if (!mMap.containsKey(k)) {
continue;
}
mMap.remove(k);
}3)apply
public void apply() {
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
public void run() {
try {
mcr.writtenToDiskLatch.await();
} catch (InterruptedException ignored) {
}
}
};
QueuedWork.add(awaitCommit);
Runnable postWriteRunnable = new Runnable() {
public void run() {
awaitCommit.run();
QueuedWork.remove(awaitCommit);
}
};
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
// Okay to notify the listeners before it's hit disk
// because the listeners should always get the same
// SharedPreferences instance back, which has the
// changes reflected in memory.
notifyListeners(mcr);
}其实完成和commit 的功能差不多。
两者的区别:
/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing. This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call apply wins.
*
* <p>Unlike {@link #commit}, which writes its preferences out
* to persistent storage synchronously, {@link #apply}
* commits its changes to the in-memory
* {@link SharedPreferences} immediately but starts an
* asynchronous commit to disk and you won't be notified of
* any failures. If another editor on this
* {@link SharedPreferences} does a regular {@link #commit}
* while a {@link #apply} is still outstanding, the
* {@link #commit} will block until all async commits are
* completed as well as the commit itself.
*
* <p>As {@link SharedPreferences} instances are singletons within
* a process, it's safe to replace any instance of {@link #commit} with
* {@link #apply} if you were already ignoring the return value.
*
* <p>You don't need to worry about Android component
* lifecycles and their interaction with <code>apply()</code>
* writing to disk. The framework makes sure in-flight disk
* writes from <code>apply()</code> complete before switching
* states.
*
* <p class='note'>The SharedPreferences.Editor interface
* isn't expected to be implemented directly. However, if you
* previously did implement it and are now getting errors
* about missing <code>apply()</code>, you can simply call
* {@link #commit} from <code>apply()</code>.
*/区别1:
commit 是有返回值的,表示是否成功;而apply是没有的。
由于在一个进程中,sharedPreference是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。
区别2:
commit 同步提交到disk 中;而apply 是立马存在内存中,然后异步去存储到disk中,中间是收不到失败的信息的。
不用去担心线程安全问题, 因为如果一个其他的线程去commit,而刚好有一个还没有完成的apply,commit会被阻塞到异步线程提交完成。
请转载的朋友标明出处~~
前言:之前 SharedPreference 实现不同进程间的数据共享 中谈了一下数据共享,最近在用到这一块的时候感觉有点模糊,索性就看一下source code,分享一下~
一、使用
分两个函数:
private void getDataFromSP() { SharedPreferences sp = getSharedPreferences("sp_name", Context.MODE_PRIVATE); int value1 = sp.getInt("field_1", 0); String value2 = sp.getString("field_2", ""); }
private void setDataToSp() { SharedPreferences sp = getSharedPreferences("sp_name", Context.MODE_PRIVATE); Editor editor = sp.edit(); editor.putInt("field_1", 0); editor.putString("field_2", ""); editor.commit(); }
二、source code 详解
1、获取对象
code 中拖过getSharePreferences 来获取SharedPreferences 的对象,调用过程不说了,说一下实现:
@Override public SharedPreferences getSharedPreferences(String name, int mode) { SharedPreferencesImpl sp; synchronized (ContextImpl.class) { if (sSharedPrefs == null) { sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>(); } final String packageName = getPackageName(); ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName); if (packagePrefs == null) { packagePrefs = new ArrayMap<String, SharedPreferencesImpl>(); sSharedPrefs.put(packageName, packagePrefs); } // At least one application in the world actually passes in a null // name. This happened to work because when we generated the file name // we would stringify it to "null.xml". Nice. if (mPackageInfo.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.KITKAT) { if (name == null) { name = "null"; } } sp = packagePrefs.get(name); if (sp == null) { File prefsFile = getSharedPrefsFile(name); sp = new SharedPreferencesImpl(prefsFile, mode); packagePrefs.put(name, sp); return sp; } } if ((mode & Context.MODE_MULTI_PROCESS) != 0 || getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) { // If somebody else (some other process) changed the prefs // file behind our back, we reload it. This has been the // historical (if undocumented) behavior. sp.startReloadIfChangedUnexpectedly(); } return sp; }通过code可以看到几点:
1)一个package 可以创建多个xml,每个xml代表一个SharedPreferences 对象
2)如果xml 没有的时候会新建文件,新建一个SharedPreferences 对象
3)参数mode是 Context.MODE_MULTI_PROCESS 的时候,可以允许多进程操作
4)SharedPreferences 真正实现的class 是SharedPreferencesImpl
2、读取信息
SharedPreferences 从source code看,是一个interface:
public interface SharedPreferences {}所以是需要实现的,实现它的地方之前讲过是 SharedPreferencesImpl.java
几个get 的方法:
public int getInt(String key, int defValue) { synchronized (this) { awaitLoadedLocked(); Integer v = (Integer)mMap.get(key); return v != null ? v : defValue; } }
public Set<String> getStringSet(String key, Set<String> defValues) { synchronized (this) { awaitLoadedLocked(); Set<String> v = (Set<String>) mMap.get(key); return v != null ? v : defValues; } }
public boolean getBoolean(String key, boolean defValue) { synchronized (this) { awaitLoadedLocked(); Boolean v = (Boolean)mMap.get(key); return v != null ? v : defValue; } }从code 看,是在SharedPreferencesImpl 中有个mMap的东西:
private Map<String, Object> mMap;step 1 中讲过在getSharedPreferences的时候会新建一个SharedPreferencesImpl 对象:
SharedPreferencesImpl(File file, int mode) { mFile = file; mBackupFile = makeBackupFile(file); mMode = mode; mLoaded = false; mMap = null; startLoadFromDisk(); } private void startLoadFromDisk() { synchronized (this) { mLoaded = false; } new Thread("SharedPreferencesImpl-load") { public void run() { synchronized (SharedPreferencesImpl.this) { loadFromDiskLocked(); } } }.start(); }最终:
map = XmlUtils.readMapXml(str);
3、存储数据
使用的时候SharedPreferences 用内部类Editor,可是Source code 中Editor 也是interface ,实现的地方是EditorImpl
public final class EditorImpl implements Editor { private final Map<String, Object> mModified = Maps.newHashMap(); private boolean mClear = false; ...... ...... }可以看到会新建一个Map,所以,在使用的时候一直put,就是存进这个map 中。
几个put 的接口:
public Editor putString(String key, String value) { synchronized (this) { mModified.put(key, value); return this; } } public Editor putStringSet(String key, Set<String> values) { synchronized (this) { mModified.put(key, (values == null) ? null : new HashSet<String>(values)); return this; } } public Editor putInt(String key, int value) { synchronized (this) { mModified.put(key, value); return this; } } public Editor putLong(String key, long value) { synchronized (this) { mModified.put(key, value); return this; } } public Editor putFloat(String key, float value) { synchronized (this) { mModified.put(key, value); return this; } } public Editor putBoolean(String key, boolean value) { synchronized (this) { mModified.put(key, value); return this; } }put 完后最终调用commit 来完成存储:
public boolean commit() { MemoryCommitResult mcr = commitToMemory(); SharedPreferencesImpl.this.enqueueDiskWrite( mcr, null /* sync write on this thread okay */); try { mcr.writtenToDiskLatch.await(); } catch (InterruptedException e) { return false; } notifyListeners(mcr); return mcr.writeToDiskResult; }存储过程暂时不介绍,注意的是最后的Listener:
private void notifyListeners(final MemoryCommitResult mcr) { if (mcr.listeners == null || mcr.keysModified == null || mcr.keysModified.size() == 0) { return; } if (Looper.myLooper() == Looper.getMainLooper()) { for (int i = mcr.keysModified.size() - 1; i >= 0; i--) { final String key = mcr.keysModified.get(i); for (OnSharedPreferenceChangeListener listener : mcr.listeners) { if (listener != null) { listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key); } } } } else { // Run this function on the main thread. ActivityThread.sMainThreadHandler.post(new Runnable() { public void run() { notifyListeners(mcr); } }); } }onSharedPreferenceChanged 是肯定要在主线程中调用的。
4、Editor 其他的一些接口
1)clear
public Editor clear() { synchronized (this) { mClear = true; return this; } }在commit 的时候会判断 mClear:
if (mClear) { if (!mMap.isEmpty()) { mcr.changesMade = true; mMap.clear(); } mClear = false; ...... ...... }2)remove
public Editor remove(String key) { synchronized (this) { mModified.put(key, this); return this; } }
刚开始看到这个很奇怪,功能是remove的,为什么会put呢,因为是两份map操作,这个临时的map,即mModified不知道mMap 里面有没有这个,所以,就put 了this。
在commit的时候会比较每个元素,当碰到了this 之后会确认mMap 里面是否存在,没有就算了,有就remove掉:
if (v == this || v == null) {
if (!mMap.containsKey(k)) {
continue;
}
mMap.remove(k);
}3)apply
public void apply() {
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
public void run() {
try {
mcr.writtenToDiskLatch.await();
} catch (InterruptedException ignored) {
}
}
};
QueuedWork.add(awaitCommit);
Runnable postWriteRunnable = new Runnable() {
public void run() {
awaitCommit.run();
QueuedWork.remove(awaitCommit);
}
};
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
// Okay to notify the listeners before it's hit disk
// because the listeners should always get the same
// SharedPreferences instance back, which has the
// changes reflected in memory.
notifyListeners(mcr);
}其实完成和commit 的功能差不多。
两者的区别:
/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing. This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call apply wins.
*
* <p>Unlike {@link #commit}, which writes its preferences out
* to persistent storage synchronously, {@link #apply}
* commits its changes to the in-memory
* {@link SharedPreferences} immediately but starts an
* asynchronous commit to disk and you won't be notified of
* any failures. If another editor on this
* {@link SharedPreferences} does a regular {@link #commit}
* while a {@link #apply} is still outstanding, the
* {@link #commit} will block until all async commits are
* completed as well as the commit itself.
*
* <p>As {@link SharedPreferences} instances are singletons within
* a process, it's safe to replace any instance of {@link #commit} with
* {@link #apply} if you were already ignoring the return value.
*
* <p>You don't need to worry about Android component
* lifecycles and their interaction with <code>apply()</code>
* writing to disk. The framework makes sure in-flight disk
* writes from <code>apply()</code> complete before switching
* states.
*
* <p class='note'>The SharedPreferences.Editor interface
* isn't expected to be implemented directly. However, if you
* previously did implement it and are now getting errors
* about missing <code>apply()</code>, you can simply call
* {@link #commit} from <code>apply()</code>.
*/区别1:
commit 是有返回值的,表示是否成功;而apply是没有的。
由于在一个进程中,sharedPreference是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。
区别2:
commit 同步提交到disk 中;而apply 是立马存在内存中,然后异步去存储到disk中,中间是收不到失败的信息的。
不用去担心线程安全问题, 因为如果一个其他的线程去commit,而刚好有一个还没有完成的apply,commit会被阻塞到异步线程提交完成。
相关文章推荐
- Deferred 异步模型
- windows下sublime text的node.js开发环境搭建
- jquery 跨域获取网页数据
- SharePoint 2007 IT Professional--如何部署My Site?
- 安装mysql 报Fatal error: cannot allocate memory for the buffer pool
- 通过Jquery.cookie.js实现展示浏览网页的历史记录超管用
- node.js学习二(Express4.x)
- JS 函数参数
- 你不知道的JavaScript--Item20 作用域与作用域链(scope chain)
- 你不知道的JavaScript--Item20 作用域与作用域链(scope chain)
- ReactJs入门教程
- node.js学习一(node入门)
- js刷新框架子页面的七种方法
- Xfermode入门
- 关于NopCommerce3.6版的@Html.Widget(“home_page_top”)的说明
- jQuery的一些简单语法总结
- jQuery 实现图片切换
- jQuery实现分章节锚点“回到顶部”动画特效代码
- jsTree简单使用说明(适用于做权限)
- 解决 jquery.form.js和springMVC上传 MultipartFile取不到信息