标签:android style blog color io os 使用 java ar
突然想到个问题,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 it
24 return sp;
25 }
26 File backup = makeBackupFile(prefsFile);
27 if (backup.exists()) {
28 prefsFile.delete();
29 backup.renameTo(prefsFile);
30 }
31
32 // Debugging
33 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.java 52 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.this 58 // - acquire mWritingToDiskLock before EditorImpl.this 59 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.java 273 public Editor edit() { 274 // TODO: remove the need to call awaitLoadedLocked() when 275 // requesting an editor. will require some work on the 276 // 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 } 284 285 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; 306 307 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 made 389 private MemoryCommitResult commitToMemory() { 390 MemoryCommitResult mcr = new MemoryCommitResult(); 391 synchronized (SharedPreferencesImpl.this) { 392 // We optimistically don‘t make a deep copy until 393 // a memory commit comes in when we‘re already 394 // writing to disk. 395 if (mDiskWritesInFlight > 0) { 396 // We can‘t modify our mMap as a currently 397 // in-flight write owns it. Clone it before 398 // modifying it. 399 // noinspection unchecked 400 mMap = new HashMap<String, Object>(mMap); 401 } 402 mcr.mapToWriteToDisk = mMap; 403 mDiskWritesInFlight++; 404 405 boolean hasListeners = mListeners.size() > 0; 406 if (hasListeners) { 407 mcr.keysModified = new ArrayList<String>(); 408 mcr.listeners = 409 new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet()); 410 } 411 412 synchronized (this) { 413 if (mClear) { 414 if (!mMap.isEmpty()) { 415 mcr.changesMade = true; 416 mMap.clear(); 417 } 418 mClear = false; 419 } 420 421 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 mutation 425 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 = mMap.get(k); 433 if (existingValue != null && existingValue.equals(v)) { 434 continue; 435 } 436 } 437 mMap.put(k, v); 438 } 439 440 mcr.changesMade = true; 441 if (hasListeners) { 442 mcr.keysModified.add(k); 443 } 444 } 445 446 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 read 566 if (mFile.exists()) { 567 if (!mcr.changesMade) { 568 // If the file already exists, but no changes were 569 // made to the underlying map, it‘s wasteful to 570 // re-write the file. Return as if we wrote it 571 // 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 " + mFile 578 + " to backup file " + mBackupFile); 579 mcr.setDiskWriteResult(false); 580 return; 581 } 582 } else { 583 mFile.delete(); 584 } 585 } 586 587 // Attempt to write the file, delete the backup and return true as atomically as 588 // possible. If any exception occurs, delete the new file; next time we will restore 589 // 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 nothing 608 } 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 file 619 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使用时,单例,线程安全,存在缓存(二次加载快速)。
标签:android style blog color io os 使用 java ar
原文地址:http://www.cnblogs.com/asi24/p/3982790.html