一兄旬、SharedPreferences構(gòu)建:
1.1 ContextImpl.getSharedPreferences:
private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;
@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);
}
/**
* api19以下支持name = null;
*/
if (mPackageInfo.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.KITKAT) {
if (name == null) {
name = "null";
}
}
sp = packagePrefs.get(name);
if (sp == null) {
/**
* 1. 一個name對應(yīng)一個SharedPreferencesImpl;
* 2. 將File緩存在SharedPreferencesImpl中;
*/
File prefsFile = getSharedPrefsFile(name); 模塊<1.2>
sp = new SharedPreferencesImpl(prefsFile, mode); 模塊<1.3>
packagePrefs.put(name, sp);
return sp;
}
}
return sp;
}
1.2 ContextImpl.getSharedPrefsFile:
/**
* 構(gòu)建對應(yīng)的File文件;
*/
@Override
public File getSharedPrefsFile(String name) {
return makeFilename(getPreferencesDir(), name + ".xml");
}
private File makeFilename(File base, String name) {
if (name.indexOf(File.separatorChar) < 0) {
return new File(base, name);
}
}
1.3 SharedPreferencesImpl構(gòu)造函數(shù):
SharedPreferencesImpl(File file, int mode) {
mFile = file;
mBackupFile = makeBackupFile(file);
mMode = mode;
mLoaded = false;
mMap = null;
/**
* 1. 結(jié)合模塊<1.4>可知, 在使用Sp時, 需要先根據(jù)name將指定目錄下的<name>文件中的內(nèi)容全部
* 加載進(jìn)內(nèi)存中, 然后在進(jìn)行讀寫操作;
* 2. 數(shù)據(jù)量越大, 加載就越耗時, 所以這也就是為什么一直強(qiáng)調(diào)盡量不要在一個sp中存儲大量數(shù)據(jù);
*/
startLoadFromDisk(); 模塊<1.4>
}
1.4 SharedPreferencesImpl.startLoadFromDisk:
private void startLoadFromDisk() {
synchronized (this) {
mLoaded = false;
}
new Thread("SharedPreferencesImpl-load") {
public void run() {
synchronized (SharedPreferencesImpl.this) {
/**
* File中的數(shù)據(jù)加載進(jìn)Map是在子線程中進(jìn)行, 與putXXX操作如何進(jìn)行同步? 模塊<二>
*/
loadFromDiskLocked();
}
}
}.start();
}
private void loadFromDiskLocked() {
if (mLoaded) {
return;
}
if (mBackupFile.exists()) {
mFile.delete();
mBackupFile.renameTo(mFile);
}
Map map = null;
StructStat stat = null;
stat = Os.stat(mFile.getPath());
if (mFile.canRead()) {
/**
* 數(shù)據(jù)量越大, 這一塊就越耗時, 進(jìn)行g(shù)et/edit操作時如果加載沒完成會處于阻塞狀態(tài);
*/
BufferedInputStream str = null;
str = new BufferedInputStream(new FileInputStream(mFile), 16*1024);
map = XmlUtils.readMapXml(str);
}
mLoaded = true;
if (map != null) {
mMap = map;
mStatTimestamp = stat.st_mtime;
mStatSize = stat.st_size;
} else {
mMap = new HashMap<String, Object>();
}
notifyAll();
}
二、SharedPreferencesImpl.edit:
public Editor edit() {
/**
* 這里的插入操作與初始化Sp時磁盤數(shù)據(jù)加載到內(nèi)存共用同一把鎖, 如果初始化時的數(shù)據(jù)加載
* 耗時過長, 這里就會被一直阻塞;
*/
synchronized (this) {
awaitLoadedLocked();
}
return new EditorImpl();
}
private void awaitLoadedLocked() {
while (!mLoaded) {
wait();
}
}
三浑侥、EditorImpl.putXXX:
public Editor putInt(String key, int value) {
synchronized (this) {
/**
* 對于指定name的Sp, 由于sp與EditorImpl都是單例, 在結(jié)合這里的鎖對象, 所以Sp是線程安全的;
*/
mModified.put(key, value);
return this;
}
}
四枫耳、EditorImpl.commit:
4.1 EditorImpl.commit:
public boolean commit() {
/**
* 將數(shù)據(jù)從緩存集合mModified讀取到mMap中, 然后將mMap賦值給MCR;
*/
MemoryCommitResult mcr = commitToMemory(); 模塊<4.2>
/**
* 將數(shù)據(jù)從mcr.mapToWriteToDisk中寫入到磁盤中;
*/
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, null); 模塊<4.3>
try {
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
}
notifyListeners(mcr);
return mcr.writeToDiskResult;
}
4.2 EditorImpl.commitToMemory:
private MemoryCommitResult commitToMemory() {
MemoryCommitResult mcr = new MemoryCommitResult();
synchronized (SharedPreferencesImpl.this) {
if (mDiskWritesInFlight > 0) {
mMap = new HashMap<String, Object>(mMap);
}
mcr.mapToWriteToDisk = mMap;
mDiskWritesInFlight++;
boolean hasListeners = mListeners.size() > 0;
if (hasListeners) {
mcr.keysModified = new ArrayList<String>();
mcr.listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
}
synchronized (this) {
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
...
mMap.put(k, v);
mcr.changesMade = true;
if (hasListeners) {
mcr.keysModified.add(k);
}
}
mModified.clear();
}
}
return mcr;
}
- 簡而言之, EditorImpl.putXXX方法將數(shù)據(jù)緩存進(jìn)mModified中, 然后調(diào)用commit將mModified數(shù)據(jù)讀取到mMap中, 然后賦值給MemoryCommitResult.mapToWriteToDisk, 同時情況mModified;
4.3 SharedPreferencesImpl.enqueueDiskWrite:
private void enqueueDiskWrite(final MemoryCommitResult mcr, final Runnable postWriteRunnable) {
final Runnable writeToDiskRunnable = new Runnable() {
public void run() {
// 全局共用一把鎖, 寫入磁盤操作是線程同步的;
synchronized (mWritingToDiskLock) {
writeToFile(mcr); 模塊<4.4>
}
synchronized (SharedPreferencesImpl.this) {
mDiskWritesInFlight--;
}
if (postWriteRunnable != null) {
postWriteRunnable.run();
}
}
};
/**
* commit方式 ---> isFromSyncCommit = true;
* apply方式 ---> isFromSyncCommit = false;
*/
final boolean isFromSyncCommit = (postWriteRunnable == null);
if (isFromSyncCommit) {
boolean wasEmpty = false;
synchronized (SharedPreferencesImpl.this) {
/**
* 1. 結(jié)合模塊<4.2>可知, mDiskWritesInFlight默認(rèn)為0, 調(diào)用一次commit, 觸發(fā)一次
* mDiskWritesInFlight++ = 1操作, 然后在writeToDiskRunnable.run中又重置
* mDiskWritesInFlight = 0操作;
* 2. 所以調(diào)用一次commit時, mDiskWritesInFlight == 1, empty = true;
*/
wasEmpty = mDiskWritesInFlight == 1;
}
if (wasEmpty) {
/**
* 調(diào)用commit時會跳轉(zhuǎn)到這里, 觸發(fā)writeToDiskRunnable.run;
*/
writeToDiskRunnable.run();
return;
}
}
/**
* 如果是apply方式, 則會執(zhí)行到這里, 可知, writeToDiskRunnable被運行在子線程中, 然后
* 觸發(fā)writeToFile在子線程中執(zhí)行;
*/
QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable); 模塊<5.2>
}
4.4 SharedPreferencesImpl.writeToFile:
private void writeToFile(MemoryCommitResult mcr) {
if (mFile.exists()) {
if (!mcr.changesMade) {
/**
* 正如文章所說, changesMade默認(rèn)為false, mModified數(shù)據(jù)被寫入到mMap時將changesMade
* 置為true, 所以如果數(shù)據(jù)沒有發(fā)生變化, 則不對File做任何處理;
*/
mcr.setDiskWriteResult(true);
return;
}
}
try {
FileOutputStream str = createFileOutputStream(mFile);
if (str == null) {
mcr.setDiskWriteResult(false);
return;
}
XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
FileUtils.sync(str);
str.close();
/**
* 設(shè)置文件的讀寫權(quán)限;
*/
ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
final StructStat stat = Os.stat(mFile.getPath());
synchronized (this) {
mStatTimestamp = stat.st_mtime;
mStatSize = stat.st_size;
}
mBackupFile.delete();
mcr.setDiskWriteResult(true);
return;
}
catch (XmlPullParserException e) {...}
catch (IOException e) {...}
mcr.setDiskWriteResult(false);
}
五、EditorImpl.apply:
5.1 EditorImpl.apply:
public void apply() {
/**
* 將mModified數(shù)據(jù)寫入到MemoryCommitResult中;
*/
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
public void run() {
mcr.writtenToDiskLatch.await();
}
};
QueuedWork.add(awaitCommit);
Runnable postWriteRunnable = new Runnable() {
public void run() {
awaitCommit.run();
QueuedWork.remove(awaitCommit);
}
};
/**
* 將MemoryCommitResult中緩存的數(shù)據(jù)寫入到磁盤中;
*/
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable); 模塊<4.3>
notifyListeners(mcr);
}