<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## 使用 ### 獲取SharedPreferences的兩種方式 1. 調用Context對象的getSharedPreferences()方法 2. 調用Activity對象的getPreferences()方法 兩種方式的區別://待考證 1. 調用Context對象的getSharedPreferences()方法獲得的SharedPreferences對象可以被同一應用程序下的其他組件共享. 2. 調用Activity對象的getPreferences()方法獲得的SharedPreferences對象只能在該Activity中使用. ### SharedPreferences的四種操作模式: * Context.MODE\_PRIVATE:為默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容 * Context.MODE\_APPEND:模式會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件. * Context.MODE\_WORLD\_READABLE和Context.MODE\_WORLD\_WRITEABLE用來控制其他應用是否有權限讀寫該文件. * MODE\_WORLD\_READABLE:表示當前文件可以被其他應用讀取. Android N后不支持 * MODE\_WORLD\_WRITEABLE:表示當前文件可以被其他應用寫入.Android N后不支持 ## 源碼解析 ### ContextImpl ~~~ private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefsCache; private ArrayMap<String, File> mSharedPrefsPaths; @Override public SharedPreferences getSharedPreferences(String name, int mode) { ... File file; synchronized (ContextImpl.class) { if (mSharedPrefsPaths == null) { mSharedPrefsPaths = new ArrayMap<>(); } file = mSharedPrefsPaths.get(name); if (file == null) { //獲取文件路徑=當前app的data目錄下的shared_prefs目錄+"/"+SharePreferences的name+“.xml” file = getSharedPreferencesPath(name); mSharedPrefsPaths.put(name, file); } } return getSharedPreferences(file, mode); } @Override public SharedPreferences getSharedPreferences(File file, int mode) { SharedPreferencesImpl sp; synchronized (ContextImpl.class) { //讀取緩存 final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked(); sp = cache.get(file); if (sp == null) { // 如果緩存中不存在 SharedPreferences 對象 checkMode(mode); if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) { if (isCredentialProtectedStorage() && !getSystemService(UserManager.class) .isUserUnlockingOrUnlocked(UserHandle.myUserId())) { throw new IllegalStateException("SharedPreferences in credential encrypted " + "storage are not available until after user is unlocked"); } } // 構造一個 SharedPreferencesImpl 對象 sp = new SharedPreferencesImpl(file, mode); cache.put(file, 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. // 如果由其他進程修改了這個 SharedPreferences 文件,我們將會重新加載它 sp.startReloadIfChangedUnexpectedly(); } retu ~~~ * 緩存未命中, 才構造?SharedPreferences?對象,也就是說,多次調用?getSharedPreferences?方法并不會對性能造成多大影響,因為又緩存機制? * SharedPreferences?對象的創建過程是線程安全的,因為使用了?synchronize?關鍵字? * 如果命中了緩存,并且參數?mode?使用了?Context.MODE\_MULTI\_PROCESS?,那么將會調用?sp.startReloadIfChangedUnexpectedly()?方法,在?startReloadIfChangedUnexpectedly?方法中,會判斷是否由其他進程修改過這個文件,如果有,會重新從磁盤中讀取文件加載數據 ### SharedPreferencesImpl #### 初始化 ~~~ SharedPreferencesImpl(File file, int mode) { //文件 mFile = file; //回滾文件 mBackupFile = makeBackupFile(file); //模式 mMode = mode; //是否加載 mLoaded = false; //key/value 緩存 mMap = null; mThrowable = null; //開始加載 startLoadFromDisk(); } private void startLoadFromDisk() { synchronized (mLock) { mLoaded = false; } new Thread("SharedPreferencesImpl-load") { public void run() { loadFromDisk(); } }.start(); } private void loadFromDisk() { synchronized (mLock) { if (mLoaded) { return; } //如果回滾文件在 就吧原文件刪除 if (mBackupFile.exists()) { mFile.delete(); mBackupFile.renameTo(mFile); } } // Debugging if (mFile.exists() && !mFile.canRead()) { Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission"); } Map<String, Object> map = null; //文件詳情 如編輯時間等 StructStat stat = null; Throwable thrown = null; try { stat = Os.stat(mFile.getPath()); if (mFile.canRead()) { BufferedInputStream str = null; try { str = new BufferedInputStream( new FileInputStream(mFile), 16 * 1024); //將文件讀取到 map = (Map<String, Object>) XmlUtils.readMapXml(str); } catch (Exception e) { Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e); } finally { IoUtils.closeQuietly(str); } } } catch (ErrnoException e) { } catch (Throwable t) { thrown = t; } synchronized (mLock) { // 加載數據成功,設置 mLoaded 為 true mLoaded = true; mThrowable = thrown; // It's important that we always signal waiters, even if we'll make // them fail with an exception. The try-finally is pretty wide, but // better safe than sorry. try { if (thrown == null) { if (map != null) { // 將解析得到的鍵值對數據賦值給 mMap mMap = map; // 將文件的修改時間戳保存到 mStatTimestamp 中 mStatTimestamp = stat.st_mtim;= map; // 將文件的大小保存到 mStatSize mStatSize = stat.st_size; } else { mMap = new HashMap<>(); } } // In case of a thrown exception, we retain the old map. That allows // any open editors to commit and store updates. } catch (Throwable t) { mThrowable = t; } finally { //通知等待 mLock.notifyAll(); ~~~ * 如果有備份文件,直接使用備份文件進行回滾 * 第一次調用?getSharedPreferences?方法的時候,會從磁盤中加載數據,而數據的加載時通過開啟一個子線程調用?loadFromDisk?方法進行異步讀取的? * 將解析得到的鍵值對數據保存在?mMap?中? * 將文件的修改時間戳以及大小分別保存在?mStatTimestamp?以及?mStatSize?中(保存這兩個值有什么用呢?我們在分析?getSharedPreferences?方法時說過,如果有其他進程修改了文件,并且?mode?為?MODE\_MULTI\_PROCESS?,將會判斷重新加載文件。如何判斷文件是否被其他進程修改過,沒錯,根據文件修改時間以及文件大小即可知道)? * 調用?notifyAll()?方法通知喚醒其他等待線程,數據已經加載完畢 #### get ~~~ @Override @Nullable public String getString(String key, @Nullable String defValue) { synchronized (mLock) { //等待加載完畢 awaitLoadedLocked(); String v = (String)mMap.get(key); return v != null ? v : defValue; } } @Override @Nullable public Set<String> getStringSet(String key, @Nullable Set<String> defValues) { synchronized (mLock) { awaitLoadedLocked(); Set<String> v = (Set<String>) mMap.get(key); return v != null ? v : defValues; } } private void awaitLoadedLocked() { if (!mLoaded) { // 嚴苛模式 BlockGuard.getThreadPolicy().onReadFromDisk(); } while (!mLoaded) { try { mLock.wait(); } catch (InterruptedException unused) { } } } ~~~ getString?方法代碼很簡單,其他的例如?getInt?,?getFloat?方法也是一樣的原理,我們直接對這個疑問進行總結:? * getXxx?方法是線程安全的,因為使用了?synchronize?關鍵字? * getXxx?方法是直接操作內存的,直接從內存中的?mMap?中根據傳入的?key?讀取?value * getXxx?方法有可能會卡在?awaitLoadedLocked?方法,從而導致線程阻塞等待(?**什么時候會出現這種阻塞現象呢?前面我們分析過,第一次調用?****getSharedPreferences****?方法時,會創建一個線程去異步加載數據,那么假如在調用完?****getSharedPreferences****?方法之后立即調用?****getXxx****?方法,此時的?****mLoaded****?很有可能為?****false****?,這就會導致?****awaiteLoadedLocked****?方法阻塞等待,直到?****loadFromDisk****?方法加載完數據并且調用?****notifyAll****?來喚醒所有等待線程?**) #### SharedPreferencesImpl.edit() ~~~ public Editor edit() { synchronized (this) {//同步方法,保證每次只有一個線程執行加載操作 awaitLoadedLocked();//等待SharedPreferencesImpl加載到內存中,見2.7 } return new EditorImpl();//創建一個新的Editor實現。 } ~~~ #### EditorImpl ~~~ public final class EditorImpl implements Editor { private final Object mLock = new Object(); @GuardedBy("mLock") private final Map<String, Object> mModified = Maps.newHashMap(); @GuardedBy("mLock") private boolean mClear = false; public Editor putString(String key, @Nullable String value) { synchronized (mLock) { mModified.put(key, value); return this; } ~~~ 維護一個Map #### EditorImpl.commit() todo
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看