天天看點

【Android】【架構】【磁盤緩存】【SharedPreferences】整體架構 引起ANR的原因 磁盤緩存架構選型 原理 後記 學習自

整體架構

初始化的時候會加載整個XML到記憶體中

作為記憶體緩存

這也是不能跨程序的原因,任何東西隻要做緩存那就是2套資料了,即使SP做了多程序措施也無濟于事

  1. 取:從記憶體取
  2. commit:直接同步執行
  3. apply:入隊

引起ANR的原因

取是不會有ANR的,隻需要在最初加載檔案的時候讀取一次即可,後續都是從記憶體去取

commit直接在目前線程執行,雖說SP是輕量級的IO,但是至少也是IO操作,做個最簡單的IO操作,也要幾百ms

apply入隊本是對此很不錯的優化,但是最坑的一點是,Activity、Service、Broadcast都會在某些條件下等待SP隊列全部執行完成

Google美名其曰確定IO可以順利執行

【Android】【架構】【磁盤緩存】【SharedPreferences】整體架構 引起ANR的原因 磁盤緩存架構選型 原理 後記 學習自

可以參考Activity ANR的堆棧

【Android】【架構】【磁盤緩存】【SharedPreferences】整體架構 引起ANR的原因 磁盤緩存架構選型 原理 後記 學習自

waitToFinish方法會加鎖,等待queue清空

public static void waitToFinish() {
        long startTime = System.currentTimeMillis();
        boolean hadMessages = false;

        Handler handler = getHandler();

        synchronized (sLock) {
            if (handler.hasMessages(QueuedWorkHandler.MSG_RUN)) {
                // Delayed work will be processed at processPendingWork() below
                handler.removeMessages(QueuedWorkHandler.MSG_RUN);

                if (DEBUG) {
                    hadMessages = true;
                    Log.d(LOG_TAG, "waiting");
                }
            }

            // We should not delay any work as this might delay the finishers
            sCanDelay = false;
        }

        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
        try {
            processPendingWork();
        } finally {
            StrictMode.setThreadPolicy(oldPolicy);
        }

        try {
            while (true) {
                Runnable finisher;

                synchronized (sLock) {
                    finisher = sFinishers.poll();
                }

                if (finisher == null) {
                    break;
                }

                finisher.run();
            }
        } finally {
            sCanDelay = true;
        }

        synchronized (sLock) {
            long waitTime = System.currentTimeMillis() - startTime;

            if (waitTime > 0 || hadMessages) {
                mWaitTimes.add(Long.valueOf(waitTime).intValue());
                mNumWaits++;

                if (DEBUG || mNumWaits % 1024 == 0 || waitTime > MAX_WAIT_TIME_MILLIS) {
                    mWaitTimes.log(LOG_TAG, "waited: ");
                }
            }
        }
    }
           

是以解決方式是反射清理等待鎖

磁盤緩存架構選型

目前頂級項目很少會采用SP來進行磁盤緩存了,其ANR是一個繞不開的坎

先不說apply引起的ANR

很多時候,很多業務場景,對業務即時性的要求很高,是以必須采用commit的形式去做緩存

這個時候就對緩存架構的IO速度有極高的要求了

顯然SP沒有那麼高效

微信開源的MMKV是值得使用的,雖然還有一些小坑會導緻異常的ANR,但是整體上來說,是最頂級的緩存架構

原理

上面的整體架構有介紹原理了

也是比較易于了解,通俗易懂的

是以源碼細節這裡不再過多糾結了

想學習一些并發、IO的細節可以參考 https://mp.weixin.qq.com/s/qXQQb0IxrYeAFmrvXLydmA?client=tim&ADUIN=136284008&ADSESSION=1555676164&ADTAG=CLIENT.QQ.5603_.0&ADPUBNO=26882

後記

有什麼寫得錯誤、讓人費解或遺漏的地方,希望可以不吝賜教,我會馬上更改

學習自

https://mp.weixin.qq.com/s/qXQQb0IxrYeAFmrvXLydmA?client=tim&ADUIN=136284008&ADSESSION=1555676164&ADTAG=CLIENT.QQ.5603_.0&ADPUBNO=26882

https://www.jianshu.com/p/9ae0f6842689