成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

SharedPreferences源碼之我見(jiàn)

wenhai.he / 3292人閱讀

摘要:概述可以通過(guò)獲取到,它是一個(gè)接口,實(shí)現(xiàn)在源碼也僅僅只有行,相對(duì)于龐大的源碼,小很多。但是你真的了解它嗎問(wèn)題不同的里面獲取的相同嗎支持并發(fā)嗎直接保存了嗎針對(duì)上面的問(wèn)題,我們一點(diǎn)點(diǎn)來(lái)分析。但是僅僅是保存到了中,正真的是要在或之后。

說(shuō)在前面:SharedPreferences是Android中幾種重要的存儲(chǔ)數(shù)據(jù)的方式,Android開(kāi)發(fā)不會(huì)沒(méi)有人從來(lái)沒(méi)有使用過(guò),但是卻很好人會(huì)關(guān)注它是怎么實(shí)現(xiàn)的,確實(shí)SharedPreferences實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,本質(zhì)是基于文件存儲(chǔ),格式是XML形勢(shì)的,本篇文章并沒(méi)有太深的技術(shù),但絕對(duì)是不可缺少的知識(shí)。

概述

SharedPreferences可以通過(guò)Context獲取到,它是一個(gè)接口,實(shí)現(xiàn)在frameworksbasecorejavaandroidappSharedPreferencesImpl.java

源碼也僅僅只有630行,相對(duì)于龐大的Android源碼,小很多。但是你真的了解它嗎?

問(wèn)題

1、不同的Activity里面Context.getSharedPreferences()獲取的SharedPreferences相同嗎?

2、支持并發(fā)嗎?

3、SharedPreferences.putXXX()直接保存了嗎?

......

針對(duì)上面的問(wèn)題,我們一點(diǎn)點(diǎn)來(lái)分析。

獲得SharedPreferences

我們獲得SharedPreferences是通過(guò)Context.getSharedPreferences(),源碼如下:

 @Override
public SharedPreferences getSharedPreferences(String name, int mode) {
  SharedPreferencesImpl sp;
  synchronized (ContextImpl.class) {
    // 靜態(tài)的 全局唯一,緩存得到的SharedPreferences,key是app包名
    if (sSharedPrefs == null) {
          sSharedPrefs = new ArrayMap>();
    }

    // 通過(guò)每一個(gè)app的包名緩存不同的SharedPreferences,key是文件名
    // 這里就明白前面提到的第一個(gè)問(wèn)題了,一個(gè)文件對(duì)應(yīng)一個(gè)SharedPreferences
    final String packageName = getPackageName();
    ArrayMap packagePrefs = sSharedPrefs.get(packageName);
    if (packagePrefs == null) {
      packagePrefs = new ArrayMap();
      sSharedPrefs.put(packageName, packagePrefs);
    }
    
    // 略...
    // 如果以創(chuàng)建過(guò),直接從緩存中獲取返回
    sp = packagePrefs.get(name);
    if (sp == null) {
      // 如果沒(méi)有創(chuàng)建一個(gè) 文件名為data/data/packege/shared_prefs/xxx.xml
      File prefsFile = getSharedPrefsFile(name); 
      sp = new SharedPreferencesImpl(prefsFile, mode); // 創(chuàng)建實(shí)例對(duì)象
      packagePrefs.put(name, sp); // 放到緩存中
      return sp;
    }
  }
// 略...
  return sp;
}
創(chuàng)建SharedPreferences

SharedPreferences的創(chuàng)建很簡(jiǎn)單,我們先看看構(gòu)造方法:

// 僅有一個(gè)
SharedPreferencesImpl(File file, int mode) {
  mFile = file;
  mBackupFile = makeBackupFile(file); // 創(chuàng)建備份
  mMode = mode;
  mLoaded = false;
  mMap = null; // 存放鍵值對(duì)的map
  startLoadFromDisk();  // 從本地load出來(lái)
}

從構(gòu)造函數(shù)我們不難看出,SharedPreferences實(shí)際是以Map(HashMap)存儲(chǔ)數(shù)據(jù),創(chuàng)建的時(shí)候就從本地文件中讀取數(shù)據(jù)到內(nèi)存中,所以,不能存儲(chǔ)太多的數(shù)據(jù) ,否則內(nèi)存會(huì)爆掉的哦。

讀取本地文件中的數(shù)據(jù)

當(dāng)實(shí)例化的時(shí)候就會(huì)觸發(fā),一個(gè)讀取本地已存儲(chǔ)的數(shù)據(jù),

 private void loadFromDiskLocked() {
 // 讀取過(guò)就不在讀取
 if (mLoaded) {
        return;
    }
    //...
    
    Map map = null;
    StructStat stat = null;
    try {
        // 存儲(chǔ)文件狀態(tài)
        stat = Os.stat(mFile.getPath());
        if (mFile.canRead()) {
            BufferedInputStream str = null;
            try {
                str = new BufferedInputStream(
                        new FileInputStream(mFile), 16*1024);
                // 格式為xml,解析xml得到map
                map = XmlUtils.readMapXml(str);
            } catch (XmlPullParserException e) {
                Log.w(TAG, "getSharedPreferences", e);
            } catch (FileNotFoundException e) {
                Log.w(TAG, "getSharedPreferences", e);
            } catch (IOException e) {
                Log.w(TAG, "getSharedPreferences", e);
            } finally {
                IoUtils.closeQuietly(str);
            }
        }
    } catch (ErrnoException e) {
    }
    // 加載過(guò)后更改狀態(tài),如果沒(méi)有創(chuàng)建一個(gè)HashMap
    mLoaded = true;
    if (map != null) {
        mMap = map;
        mStatTimestamp = stat.st_mtime;
        mStatSize = stat.st_size;
    } else {
        mMap = new HashMap();
    }
    notifyAll();
}
獲得存儲(chǔ)的數(shù)據(jù)

得到數(shù)據(jù)通常是getXXX(),實(shí)際很簡(jiǎn)單,就是存map中取數(shù)據(jù)。

// 已getString()為例,其他一樣
@Nullable
public String getString(String key, @Nullable String defValue) {
    // 同步哦
    synchronized (this) {
        // 確保,已從文件中讀取過(guò)數(shù)據(jù)
        awaitLoadedLocked();
        // 從map中的得到數(shù)據(jù)
        String v = (String)mMap.get(key);
        return v != null ? v : defValue;
    }
}
保存數(shù)據(jù)

大家都知道保存數(shù)據(jù)是通過(guò)Editor來(lái)存儲(chǔ)的,事實(shí)上也確實(shí)是這樣的。但是putXXX()僅僅是保存到了map中,正真的是要在commit()或apply()之后。

public Editor putString(String key, @Nullable String value) {
    // 同步哦
    synchronized (this) {
            mModified.put(key, value);
            return this;
        }
    }

1、

    public boolean commit() {
        MemoryCommitResult mcr = commitToMemory();
        // 寫(xiě)數(shù)據(jù)
        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;
    }

2、

 private void enqueueDiskWrite(final MemoryCommitResult mcr, final Runnable postWriteRunnable) {
    final Runnable writeToDiskRunnable = new Runnable() {
            public void run() {
                synchronized (mWritingToDiskLock) {
                    // 往文件中寫(xiě)入數(shù)據(jù)
                    writeToFile(mcr);
                }
                synchronized (SharedPreferencesImpl.this) {
                    mDiskWritesInFlight--;
                }
                if (postWriteRunnable != null) {
                    postWriteRunnable.run();
                }
            }
        };

      // ...

    QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
}

3、

 // Note: must hold mWritingToDiskLock
private void writeToFile(MemoryCommitResult mcr) {
   // ...
    try {
        FileOutputStream str = createFileOutputStream(mFile);
        if (str == null) {
            mcr.setDiskWriteResult(false);
            return;
        }
        // 寫(xiě)入到文件中
        XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
        FileUtils.sync(str);
        str.close();
        ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
        try {
         // 更新文件的狀態(tài)
            final StructStat stat = Os.stat(mFile.getPath());
            synchronized (this) {
                mStatTimestamp = stat.st_mtime;
                mStatSize = stat.st_size;
            }
        } catch (ErrnoException e) {
            // Do nothing
        }
        // Writing was successful, delete the backup file if there is one.
        mBackupFile.delete();
        mcr.setDiskWriteResult(true);
        return;
    } catch (XmlPullParserException e) {
        Log.w(TAG, "writeToFile: Got exception:", e);
    } catch (IOException e) {
        Log.w(TAG, "writeToFile: Got exception:", e);
    }
    // Clean up an unsuccessfully written file
    if (mFile.exists()) {
        if (!mFile.delete()) {
            Log.e(TAG, "Couldn"t clean up partially-written file " + mFile);
        }
    }
    mcr.setDiskWriteResult(false);
}
總結(jié)

1、SharedPreferences有緩存

2、數(shù)據(jù)是通過(guò)map來(lái)快速訪問(wèn),所以不用擔(dān)心文件IO耗時(shí)

3、支持多線程并發(fā)

4、本質(zhì)是基于文件xml的形式

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66790.html

相關(guān)文章

  • 《CDN 我見(jiàn)》系列二:原理篇(緩存、安全)

    摘要:真正要做高性能的系統(tǒng),不僅需要在數(shù)據(jù)結(jié)構(gòu)與算法層面深入,更要從硬件操作系統(tǒng)文件系統(tǒng)底層原理等多個(gè)領(lǐng)域做更多的研究例如阿里云自研的系統(tǒng)使用了裸盤(pán)技術(shù)。 《CDN之我見(jiàn)》共由三個(gè)篇章組成,分為原理篇、詳解篇和隕坑篇。本篇章適合那些從未接觸過(guò)、或僅了解一些 CDN 專(zhuān)業(yè)術(shù)語(yǔ),想深入了解和感受 CDN 究竟是什么的同學(xué)。本次由白金老師繼續(xù)為大家分享《CDN之我見(jiàn)》系列二,主要講解緩存是什么、工...

    maxmin 評(píng)論0 收藏0
  • 《CDN 我見(jiàn)》系列二:原理篇(緩存、安全)

    摘要:真正要做高性能的系統(tǒng),不僅需要在數(shù)據(jù)結(jié)構(gòu)與算法層面深入,更要從硬件操作系統(tǒng)文件系統(tǒng)底層原理等多個(gè)領(lǐng)域做更多的研究例如阿里云自研的系統(tǒng)使用了裸盤(pán)技術(shù)。 《CDN之我見(jiàn)》共由三個(gè)篇章組成,分為原理篇、詳解篇和隕坑篇。本篇章適合那些從未接觸過(guò)、或僅了解一些 CDN 專(zhuān)業(yè)術(shù)語(yǔ),想深入了解和感受 CDN 究竟是什么的同學(xué)。本次由白金老師繼續(xù)為大家分享《CDN之我見(jiàn)》系列二,主要講解緩存是什么、工...

    rainyang 評(píng)論0 收藏0
  • 初級(jí)理解async實(shí)現(xiàn)我見(jiàn)

    摘要:在我們寫(xiě)項(xiàng)目代碼的過(guò)程中,要經(jīng)常請(qǐng)求接口數(shù)據(jù),在某些異步請(qǐng)求數(shù)據(jù)之后,將得到的值進(jìn)行處理。 在我們寫(xiě)項(xiàng)目代碼的過(guò)程中,要經(jīng)常請(qǐng)求接口數(shù)據(jù),在某些異步請(qǐng)求數(shù)據(jù)之后,將得到的值進(jìn)行處理。通俗的一句話就是,我要把這個(gè)值放到另一個(gè)函數(shù)中,按行數(shù)順序處理,即同步的概念! 例子:第一步,涉及異步函數(shù) 假設(shè)我有一個(gè)函數(shù)abc, function abc(){ //異步方法,請(qǐng)求數(shù)據(jù)得到re...

    CastlePeaK 評(píng)論0 收藏0
  • Spring框架我見(jiàn)(五)——Spring Boot

    摘要:通過(guò)我們可以更輕松地入門(mén),更簡(jiǎn)單的使用的框架。團(tuán)隊(duì)為了擺脫框架中各類(lèi)繁復(fù)紛雜的配置,使用約定優(yōu)于配置的思想,在基礎(chǔ)上整合了大量常用的第三方庫(kù)的開(kāi)發(fā)框架。這里還要說(shuō)的一點(diǎn),的出現(xiàn)并不是單純的為了簡(jiǎn)化開(kāi)發(fā),更是為做鋪墊。 說(shuō)完了Spring 我們來(lái)聊聊Spring的進(jìn)階版Spring Boot,如果你還不知道Spring Boot,那希望這篇文章能夠?yàn)槟阒该鞣较颉?Spring Boot ...

    張巨偉 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<