首页 > 代码库 > SharedPreferences小探
SharedPreferences小探
突然想到个问题,SharedPreferences线程安全么?有没有使用缓存相关的技术?
首先想到的是Activity里面的:
public abstract SharedPreferences getSharedPreferences(String name, int mode);
在android.content.Context中,我们首先找到简单的解释:
The single SharedPreferences instance that can be used to retrieve and modify the preference values.
关键字:单例,继续
1 // android.app.ContextImpl.java 2 private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs = new HashMap<String, SharedPreferencesImpl>();
3 @Override 4 public SharedPreferences getSharedPreferences(String name, int mode) { 5 SharedPreferencesImpl sp; 6 File prefsFile; 7 boolean needInitialLoad = false; 8 synchronized (sSharedPrefs) { 9 sp = sSharedPrefs.get(name);10 if (sp != null && !sp.hasFileChangedUnexpectedly()) {11 return sp;12 }13 prefsFile = getSharedPrefsFile(name);14 if (sp == null) {15 sp = new SharedPreferencesImpl(prefsFile, mode, null);16 sSharedPrefs.put(name, sp);17 needInitialLoad = true;18 }19 }20 21 synchronized (sp) {22 if (needInitialLoad && sp.isLoaded()) {23 // lost the race to load; another thread handled it24 return sp;25 }26 File backup = makeBackupFile(prefsFile);27 if (backup.exists()) {28 prefsFile.delete();29 backup.renameTo(prefsFile);30 }31 32 // Debugging33 if (prefsFile.exists() && !prefsFile.canRead()) {34 Log.w(TAG, "Attempt to read preferences file " + prefsFile + " without permission");35 }36 37 Map map = null;38 FileStatus stat = new FileStatus();39 if (FileUtils.getFileStatus(prefsFile.getPath(), stat) && prefsFile.canRead()) {40 try {41 FileInputStream str = new FileInputStream(prefsFile);42 map = XmlUtils.readMapXml(str);43 str.close();44 } catch (org.xmlpull.v1.XmlPullParserException e) {45 Log.w(TAG, "getSharedPreferences", e);46 } catch (FileNotFoundException e) {47 Log.w(TAG, "getSharedPreferences", e);48 } catch (IOException e) {49 Log.w(TAG, "getSharedPreferences", e);50 }51 }52 sp.replace(map, stat);53 }54 return sp;55 }
认识1:getSharedPreferences通过Map保证SharedPreferences单例。
继续
//SharedPreferencesImpl.java52 final class More ...SharedPreferencesImpl implements SharedPreferences {53 private static final String TAG = "SharedPreferencesImpl";54 private static final boolean DEBUG = false;55 56 // Lock ordering rules:57 // - acquire SharedPreferencesImpl.this before EditorImpl.this58 // - acquire mWritingToDiskLock before EditorImpl.this59 60 private final File mFile;61 private final File mBackupFile;62 private final int mMode;63 64 private Map<String, Object> mMap; // guarded by ‘this‘
mMap是不是editor的缓存?
//SharedPreferencesImpl.java273 public Editor edit() {274 // TODO: remove the need to call awaitLoadedLocked() when275 // requesting an editor. will require some work on the276 // Editor, but then we should be able to do:277 //278 // context.getSharedPreferences(..).edit().putString(..).apply()279 //280 // ... all without blocking.281 synchronized (this) {282 awaitLoadedLocked();283 }284285 return new EditorImpl();286 }303 public final class EditorImpl implements Editor {304 private final Map<String, Object> mModified = Maps.newHashMap();305 private boolean mClear = false;306307 public Editor putString(String key, String value) {308 synchronized (this) {309 mModified.put(key, value);310 return this;311 }312 }
认识2:每次edit会new EditorImpl ,并且EditorImpl 自带mModified缓存。
388 // Returns true if any changes were made389 private MemoryCommitResult commitToMemory() {390 MemoryCommitResult mcr = new MemoryCommitResult();391 synchronized (SharedPreferencesImpl.this) {392 // We optimistically don‘t make a deep copy until393 // a memory commit comes in when we‘re already394 // writing to disk.395 if (mDiskWritesInFlight > 0) {396 // We can‘t modify our mMap as a currently397 // in-flight write owns it. Clone it before398 // modifying it.399 // noinspection unchecked400 mMap = new HashMap<String, Object>(mMap);401 }402 mcr.mapToWriteToDisk = mMap;403 mDiskWritesInFlight++;404405 boolean hasListeners = mListeners.size() > 0;406 if (hasListeners) {407 mcr.keysModified = new ArrayList<String>();408 mcr.listeners =409 new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());410 }411412 synchronized (this) {413 if (mClear) {414 if (!mMap.isEmpty()) {415 mcr.changesMade = true;416 mMap.clear();417 }418 mClear = false;419 }420421 for (Map.Entry<String, Object> e : mModified.entrySet()) {422 String k = e.getKey();423 Object v = e.getValue();424 if (v == this) { // magic value for a removal mutation425 if (!mMap.containsKey(k)) {426 continue;427 }428 mMap.remove(k);429 } else {430 boolean isSame = false;431 if (mMap.containsKey(k)) {432 Object existingValue =http://www.mamicode.com/ mMap.get(k);433 if (existingValue != null && existingValue.equals(v)) {434 continue;435 }436 }437 mMap.put(k, v);438 }439440 mcr.changesMade = true;441 if (hasListeners) {442 mcr.keysModified.add(k);443 }444 }445446 mModified.clear();447 }448 }449 return mcr;450 }452 public boolean commit() {453 MemoryCommitResult mcr = commitToMemory();454 SharedPreferencesImpl.this.enqueueDiskWrite(455 mcr, null /* sync write on this thread okay */);456 try {457 mcr.writtenToDiskLatch.await();458 } catch (InterruptedException e) {459 return false;460 }461 notifyListeners(mcr);462 return mcr.writeToDiskResult;463 }
commit时,editor先把mModified同步到mMap,然后再写入File。
认识3:editor.commit是线程安全的。
564 private void writeToFile(MemoryCommitResult mcr) {565 // Rename the current file so it may be used as a backup during the next read566 if (mFile.exists()) {567 if (!mcr.changesMade) {568 // If the file already exists, but no changes were569 // made to the underlying map, it‘s wasteful to570 // re-write the file. Return as if we wrote it571 // out.572 mcr.setDiskWriteResult(true);573 return;574 }575 if (!mBackupFile.exists()) {576 if (!mFile.renameTo(mBackupFile)) {577 Log.e(TAG, "Couldn‘t rename file " + mFile578 + " to backup file " + mBackupFile);579 mcr.setDiskWriteResult(false);580 return;581 }582 } else {583 mFile.delete();584 }585 }586587 // Attempt to write the file, delete the backup and return true as atomically as588 // possible. If any exception occurs, delete the new file; next time we will restore589 // from the backup.590 try {591 FileOutputStream str = createFileOutputStream(mFile);592 if (str == null) {593 mcr.setDiskWriteResult(false);594 return;595 }596 XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);597 FileUtils.sync(str);598 str.close();599 ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);600 try {601 final StructStat stat = Libcore.os.stat(mFile.getPath());602 synchronized (this) {603 mStatTimestamp = stat.st_mtime;604 mStatSize = stat.st_size;605 }606 } catch (ErrnoException e) {607 // Do nothing608 }609 // Writing was successful, delete the backup file if there is one.610 mBackupFile.delete();611 mcr.setDiskWriteResult(true);612 return;613 } catch (XmlPullParserException e) {614 Log.w(TAG, "writeToFile: Got exception:", e);615 } catch (IOException e) {616 Log.w(TAG, "writeToFile: Got exception:", e);617 }618 // Clean up an unsuccessfully written file619 if (mFile.exists()) {620 if (!mFile.delete()) {621 Log.e(TAG, "Couldn‘t clean up partially-written file " + mFile);622 }623 }624 mcr.setDiskWriteResult(false);625 }
认识4:存在mBackupFile,直接操作mFile,如果出现问题,恢复备份。
总结:SharedPreferences使用时,单例,线程安全,存在缓存(二次加载快速)。
SharedPreferences小探
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。