天天看點

[Android] 緩存機制 實作原理 Bitmap的緩存 使用SQLite進行緩存 檔案緩存

  把不需要實時更新的資料緩存下來,通過時間或者其他因素 來判别是讀緩存還是網絡請求,這樣可以緩解伺服器壓力,一定程度上提高應用響應速度,并且支援離線閱讀。 

  在許多的情況下(像 listview, gridview 或 viewpager 之類的元件 )我們需要一次性加載大量的圖檔,在螢幕上顯示的圖檔和所有待顯示的圖檔有可能需要馬上就在螢幕上無限制的進行滾動、切換。

  像listview, gridview 這類元件,它們的子項當不可見時,所占用的記憶體會被回收以供正在前台顯示子項使用。垃圾回收器也會釋放你已經加載了的圖檔占用的記憶體。如果你想讓你的ui運作流暢的話,就不應該每次顯示時都去重新加載圖檔。保持一些記憶體和檔案緩存就變得很有必要了。

  通過預先消耗應用的一點記憶體來存儲資料,便可快速的為應用中的元件提供資料,是一種典型的以空間換時間的政策。 

lrucache 類(android v4 support library 類庫中開始提供)非常适合來做圖檔緩存任務 ,它可以使用一個linkedhashmap 的強引用來儲存最近使用的對象,并且當它儲存的對象占用的記憶體總和超出了為它設計的最大記憶體時會把不經常使用的對象成員踢出以供垃圾回收器回收。

  給lrucache 設定一個合适的記憶體大小,需考慮如下因素:

還剩餘多少記憶體給你的activity或應用使用

螢幕上需要一次性顯示多少張圖檔和多少圖檔在等待顯示

手機的大小和密度是多少(密度越高的裝置需要越大的 緩存)

圖檔的尺寸(決定了所占用的記憶體大小)

圖檔的通路頻率(頻率高的在記憶體中一直儲存)

儲存圖檔的品質(不同像素的在不同情況下顯示)

具體的要根據應用圖檔使用的具體情況來找到一個合适的解決辦法,一個設定 lrucache 例子:

  當為imageview加載一張圖檔時,會先在lrucache 中看看有沒有緩存這張圖檔,如果有的話直接更新到imageview中,如果沒有的話,一個背景線程會被觸發來加載這張圖檔。

在圖檔加載的task中,需要把加載好的圖檔加入到記憶體緩存中。

  記憶體緩存能夠快速的擷取到最近顯示的圖檔,但不一定就能夠擷取到。當資料集過大時很容易把記憶體緩存填滿(如gridview )。你的應用也有可能被其它的任務(比如來電)中斷進入到背景,背景應用有可能會被殺死,那麼相應的記憶體緩存對象也會被銷毀。 當你的應用重新回到前台顯示時,你的應用又需要一張一張的去加載圖檔了。

 磁盤檔案緩存能夠用來處理這些情況,儲存處理好的圖檔,當記憶體緩存不可用的時候,直接讀取在硬碟中儲存好的圖檔,這樣可以有效的減少圖檔加載的次數。讀取磁盤檔案要比直接從記憶體緩存中讀取要慢一些,而且需要在一個ui主線程外的線程中進行,因為磁盤的讀取速度是不能夠保證的,磁盤檔案緩存顯然也是一種以空間換時間的政策。

  如果圖檔使用非常頻繁的話,一個 contentprovider 可能更适合代替去存儲緩存圖檔,比如圖檔gallery 應用。

  下面是一個disklrucache的部分代碼:

  不能在ui主線程中進行這項操作,因為初始化磁盤緩存也需要對磁盤進行操作。上面的程式片段中,一個鎖對象確定了磁盤緩存沒有初始化完成之前不能夠對磁盤緩存進行通路。

   記憶體緩存在ui線程中進行檢測,磁盤緩存在ui主線程外的線程中進行檢測,當圖檔處理完成之後,分别存儲到記憶體緩存和磁盤緩存中。

  由于應用在運作的時候裝置配置參數可能會發生改變,比如裝置朝向改變,會導緻android銷毀你的activity然後按照新的配置重新開機,這種情況下,我們要避免重新去加載處理所有的圖檔,讓使用者能有一個流暢的體驗。

 使用fragment 能夠把記憶體緩存對象傳遞到新的activity執行個體中,調用setretaininstance(true)) 方法來保留fragment執行個體。當activity重新建立好後, 被保留的fragment依附于activity而存在,通過fragment就可以擷取到已經存在的記憶體緩存對象了,這樣就可以快速的擷取到圖檔,并設定到imageview上,給使用者一個流暢的體驗。

下面是一個示例程式片段:

  可以在不适用fragment(沒有界面的服務類fragment)的情況下旋轉裝置螢幕。在保留緩存的情況下,你應該能發現填充圖檔到activity中幾乎是瞬間從記憶體中取出而沒有任何延遲的感覺。任何圖檔優先從記憶體緩存擷取,沒有的話再到硬碟緩存中找,如果都沒有,那就以普通方式加載圖檔。 

參考:

<a href="http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html">caching bitmaps</a>

<a href="http://developer.android.com/reference/android/util/lrucache.html">lrucache</a>

  注意:緩存的資料庫是存放在/data/data//databases/目錄下,是占用記憶體空間的,如果緩存累計,容易浪費記憶體,需要及時清理緩存。

  思路和一般緩存一樣,把需要的資料存儲在檔案中,下次加載時判斷檔案是否存在和過期(使用file.lastmodified()方法得到檔案的最後修改時間,與目前時間判斷),存在并未過期就加載檔案中的資料,否則請求伺服器重新下載下傳。

  注意,無網絡環境下就預設讀取檔案緩存中的。

原文位址:http://blog.csdn.net/amazing7/article/details/51353817