码迷,mamicode.com
首页 > 其他好文 > 详细

SharedPreferences小探

时间:2014-09-20 03:33:56      阅读:479      评论:0      收藏:0      [点我收藏+]

标签: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使用时,单例,线程安全,存在缓存(二次加载快速)。

SharedPreferences小探

标签:android   style   blog   color   io   os   使用   java   ar   

原文地址:http://www.cnblogs.com/asi24/p/3982790.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!