最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android文件存儲SharedPreferences源碼解析

 更新時間:2022年08月26日 15:11:17   作者:niuyongzhi  
SharedPreferences是安卓平臺上一個輕量級的存儲類,用來保存應(yīng)用的一些常用配置,比如Activity狀態(tài),Activity暫停時,將此activity的狀態(tài)保存到SharedPereferences中;當(dāng)Activity重載,系統(tǒng)回調(diào)方法onSaveInstanceState時,再從SharedPreferences中將值取出

1.我們都知道SharedPreferences 是android可以用來存放key value的的文件。

        SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("key","value");
        editor.commit();
    SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("key","value");
        editor.apply();

SharedPreferences是一個接口。getSharedPreferences 拿到的是它的實現(xiàn)類SharedPreferencesImpl。

ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);
public SharedPreferences getSharedPreferences(String name, int mode) {
	   if (sp == null) {
		 File prefsFile = getSharedPrefsFile(name);
		 sp = new SharedPreferencesImpl(prefsFile, mode);
		 packagePrefs.put(name, sp);
		 return sp;
     }
}

在構(gòu)造函數(shù)中,會把存儲的鍵值對保存到一個hashMap中

  SharedPreferencesImpl(File file, int mode) {
        mFile = file;
        mBackupFile = makeBackupFile(file);
        mMode = mode;
        mLoaded = false;
        mMap = null;
        //讀取文件中存儲的key value,并存到全局變量mMap中
        startLoadFromDisk();
    }
  private void loadFromDiskLocked() {
    .......
         str = new BufferedInputStream(
                            new FileInputStream(mFile), 16*1024);
         map = XmlUtils.readMapXml(str);
        if (map != null) {
               mMap = map;
               mStatTimestamp = stat.st_mtime;
               mStatSize = stat.st_size;
       } else {
           mMap = new HashMap<String, Object>();
       }
    }

當(dāng)我們getString等取值的時候,就是從這個mMap中取的。

    get方法就是從這個map中讀取。
public String getString(String key, String defValue) {
        synchronized (this) {
            awaitLoadedLocked();
            String v = (String)mMap.get(key);
            return v != null ? v : defValue;
        }
    }

2. sharedPrefrence存數(shù)據(jù),有兩種方式,commit和apply。

sp.edit()拿到的也是一個接口,Editor,實現(xiàn)類是EditorImpl。

 SharedPreferences.Editor editor = sp.edit();
 public Editor edit() {
     return new EditorImpl();
 }

當(dāng)調(diào)用putString(String key, String value)時,先保存到了一個map中

  private final Map<String, Object> mModified = Maps.newHashMap();
 public Editor putString(String key, String value) {
        synchronized (this) {
            //將要修改的key value,存放到map中
            mModified.put(key, value);
            return this;
        }
}

那么commit和apply的區(qū)別是什么?

1).commit有返回值是一個boolean類型。

apply沒有返回值,返回的是void。

2)commit是同步存儲,所以必須拿到返回值,代碼才能往下走,否則會阻塞在這。

apply是異步存儲,直接丟在了一個線程中執(zhí)行,我們不必等待他的返回結(jié)果。

直接看源碼

  public boolean commit() {
	MemoryCommitResult mcr = commitToMemory();
	SharedPreferencesImpl.this.enqueueDiskWrite(
		mcr, null /* sync write on this thread okay */);
	try {
		mcr.writtenToDiskLatch.await();
	} catch (InterruptedException e) {
		return false;
	}
	notifyListeners(mcr);
	return mcr.writeToDiskResult;
}
public void apply() {
	final MemoryCommitResult mcr = commitToMemory();
	final Runnable awaitCommit = new Runnable() {
			public void run() {
				try {
					mcr.writtenToDiskLatch.await();
				} catch (InterruptedException ignored) {
				}
			}
		};
	QueuedWork.add(awaitCommit);
	Runnable postWriteRunnable = new Runnable() {
			public void run() {
				awaitCommit.run();
				QueuedWork.remove(awaitCommit);
			}
		};
	SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
	notifyListeners(mcr);
}

分析源碼

commit和apply都調(diào)用了這行代碼,

final MemoryCommitResult mcr = commitToMemory();

和private void enqueueDiskWrite(final MemoryCommitResult mcr,

final Runnable postWriteRunnable) ;

這倆的不同在于第二個參數(shù) Runnable postWriteRunnable。commit傳的是一個null,而apply傳的是一個Runnable對象。這個參數(shù)很關(guān)鍵,后面會根據(jù)這個參數(shù)進(jìn)行判斷,選擇是異步存儲還是同步存儲。

先看commitToMemory()是如何實現(xiàn)的。

這個方法是將要修改的鍵值對(存在mModified中),和文件中的的全量鍵值對(存在mMap中),

進(jìn)行比對,把更新后的map賦值給 mcr.mapToWriteToDisk = mMap;

   private MemoryCommitResult commitToMemory() {
          MemoryCommitResult mcr = new MemoryCommitResult();
           //mMap存儲了文件中所有的鍵值對。
           mcr.mapToWriteToDisk = mMap;
           對要新增或修改的鍵值對進(jìn)行遍歷。并添加到mMap中
            for (Map.Entry<String, Object> e : mModified.entrySet()) {
                       String k = e.getKey();
                       Object v = e.getValue();
                if (mMap.containsKey(k)) {
                   Object existingValue = mMap.get(k);
                   if (existingValue != null && existingValue.equals(v)) {
                       continue;
                   }
               }
               mMap.put(k, v);
            }
            mcr.changesMade = true;
            mModified.clear();
         return mcr;
   }

在看第二個方法enqueueDiskWrite(mrc,runnable)。

如果是commit方式存儲,runnable==null。則調(diào)用writeToDiskRunnable.run();進(jìn)行存儲,這個方法是同步的。

如果是apply方式存儲,runnable!=null。會直接放進(jìn)一個線程池中執(zhí)行。

QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);

這也就是為什么apply是異步存儲。

  注意第二個參數(shù),commit傳的是null。apply傳的是一個postWriteRunnable
   private void enqueueDiskWrite(final MemoryCommitResult mcr,
                                     final Runnable postWriteRunnable) {
           final Runnable writeToDiskRunnable = new Runnable() {
                   public void run() {
                       synchronized (mWritingToDiskLock) {
                           writeToFile(mcr);
                       }
                       synchronized (SharedPreferencesImpl.this) {
                           mDiskWritesInFlight--;
                       }
                       if (postWriteRunnable != null) {
                           postWriteRunnable.run();
                       }
                   }
               };
           //根據(jù) postWriteRunnable 是不是null來區(qū)分是commit方式還是apply方式
           final boolean isFromSyncCommit = (postWriteRunnable == null);
           // Typical #commit() path with fewer allocations, doing a write on
           // the current thread.
           //如果是commit方式,上面的注釋很也說明了commit是在當(dāng)前線程執(zhí)行的文件存儲。
           if (isFromSyncCommit) {
               boolean wasEmpty = false;
               synchronized (SharedPreferencesImpl.this) {
                   wasEmpty = mDiskWritesInFlight == 1;
               }
               if (wasEmpty) {
                   //直接調(diào)用Runnable的run方法。在當(dāng)前線程執(zhí)行文件的存儲。所以是同步方式
                   writeToDiskRunnable.run();
                   return;
               }
           }
            // 如果是applay方式,上面代碼不會執(zhí)行,也就不會return。
            //則會把存儲文件的方法放到一個線程池中去執(zhí)行
           QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
       }

然后在看看writeToFile(MemoryCommitResult mcr)。將修改后的鍵值對,保存入文件中。

先是對源文件做了一個備份,然后全量的寫入文件。

如果寫成功,會將備份文件刪除。

如果寫文件時出現(xiàn)異常,則會將備份文件恢復(fù)。

 private void writeToFile(MemoryCommitResult mcr) {
            //在寫文件前,先將源文件進(jìn)行一個備份
             if (!mBackupFile.exists()) {
                 if (!mFile.renameTo(mBackupFile)) {
                     mcr.setDiskWriteResult(false);
                     return;
                 }
             } else { //如果備份文件存在,則將源文件刪掉
                 mFile.delete();
             }
          FileOutputStream str = createFileOutputStream(mFile);
            //將文件中所有的keyvalue,保護(hù)要修改的,全量存入新的文件中。
            XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
            FileUtils.sync(str);
            str.close();
            ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
            // Writing was successful, delete the backup file if there is one.
            //刪除備份的文件
            mBackupFile.delete();
            mcr.setDiskWriteResult(true);
 }

到此這篇關(guān)于Android文件存儲SharedPreferences源碼解析的文章就介紹到這了,更多相關(guān)Android SharedPreferences內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android仿網(wǎng)易云音樂播放界面

    Android仿網(wǎng)易云音樂播放界面

    這篇文章主要為大家詳細(xì)介紹了Android仿網(wǎng)易云音樂播放界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • android繪制圓形圖片的兩種方式示例

    android繪制圓形圖片的兩種方式示例

    本篇文章主要介紹了android繪制圓形圖片的兩種方式,具有一定的參考價值,有興趣的可以了解一下。
    2017-01-01
  • Android中ImageView實現(xiàn)選擇本地圖片并顯示功能

    Android中ImageView實現(xiàn)選擇本地圖片并顯示功能

    本文主要介紹了android中ImageView實現(xiàn)選擇本地圖片并顯示功能的示例代碼。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-04-04
  • Android開發(fā) OpenGL ES繪制3D 圖形實例詳解

    Android開發(fā) OpenGL ES繪制3D 圖形實例詳解

    這篇文章主要介紹了Android開發(fā) OpenGL ES繪制3D 圖形實例詳解的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • Flutter自定義彈窗Dialog效果

    Flutter自定義彈窗Dialog效果

    這篇文章主要為大家詳細(xì)介紹了Flutter自定義彈窗Dialog效果,含底部抽屜,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Android App中進(jìn)行語言的切換

    Android App中進(jìn)行語言的切換

    這篇文章主要介紹了Android App中如何進(jìn)行語言的切換,幫助大家更好的理解和學(xué)習(xí)使用Android app,感興趣的朋友可以了解下
    2021-03-03
  • Unity同步/異步調(diào)用Android的方法實例

    Unity同步/異步調(diào)用Android的方法實例

    unity在Android端開發(fā)的時候,免不了要調(diào)用Java,下面這篇文章主要給大家介紹了關(guān)于Unity同步/異步調(diào)用Android的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • Android 應(yīng)用的全屏和非全屏實現(xiàn)代碼

    Android 應(yīng)用的全屏和非全屏實現(xiàn)代碼

    這篇文章主要介紹了Android 應(yīng)用的全屏和非全屏實現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Android結(jié)合xml實現(xiàn)幀動畫

    Android結(jié)合xml實現(xiàn)幀動畫

    將一組動作相近的圖片組合在一起,然后按照一定的時間來播放,就會形成一個動畫,我們可以稱之為幀動畫。在 Android 中可通過結(jié)合 xml 的方式來輕松實現(xiàn)。
    2021-05-05
  • Android實現(xiàn)密碼隱藏和顯示

    Android實現(xiàn)密碼隱藏和顯示

    這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)密碼隱藏和顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評論

鄂州市| 鸡泽县| 晋中市| 兴和县| 沾益县| 宁晋县| 广德县| 和田市| 临澧县| 商河县| 永靖县| 章丘市| 柞水县| 新兴县| 阿瓦提县| 鸡泽县| 得荣县| 醴陵市| 北辰区| 福州市| 广州市| 中西区| 广昌县| 泊头市| 通化市| 仙桃市| 喀什市| 基隆市| 明水县| 宽甸| 白朗县| 泊头市| 岳阳县| 青田县| 专栏| 湖北省| 牙克石市| 公安县| 承德县| 高阳县| 太仆寺旗|