為了快速查詢會被多次呼叫的資料,或者構建比較廢時的例項,我們一般使用快取的方法。快取的基本概念大體上差不多,這裡就不再重複,有興趣的可以檢視維基百科的介紹

快取有很多的實現方式,技巧性還有坑都很多,今天我給大家介紹一些非通用的方法,可以巧妙地幫大家簡單實現一些記憶體快取。

SupplierMemoize

SQLite是Android裡常用的一種資料儲存方式,在訪問資料庫資料時需要通過SQLiteOpenHelper

一份好的資料庫連線程式碼應該能解決以下幾個問題: a) 構建例項比較費資源 b) 資料庫連線最好能複用 c) onUpdate等方法在執行時不能和其他例項構成衝突。

這裡可以很簡單的這樣寫

Suppliers.memoize(new Supplier<SQLiteOpenHelper>() {  
  @Override
  public SQLiteOpenHelper get() {
    return new ...;
  }
})

這段程式碼利用了Guava提供的一些輔助方法實現SupplierMemoize和邏輯。顧名思義,Supplier一般被用作factorygeneratorbuilderclosureMemoize類似於快取這種概念,它一旦生成了一個例項,在以後的呼叫中都會返回同一例項,而且,執行緒安全。

這樣寫有幾個好處,一是需要時才去構建例項,並不會在一開始就去阻塞程式的執行,二是它很簡單的用memoize實現了快取,保證只有一個例項生成。

程式碼注入

Glow是程式碼注入的重度使用者,它使我們的程式碼更加結構化,清晰,簡單,同時還節省了不少的開發時間。

Dagger 2是我們實現注入的刀具,有興趣的同學應該去網站多瞭解一下相關的內容。除了注入,它還有一些附贈功能,而這些恰巧能被我們用來實現快取,而且還很簡單,我們只需要額外用到幾個annotation或介面而已。

@Singleton

相信大家對這個應該比較熟悉,這可是面試時的常問問題。簡單來說,它就是單例。因為所以,用了它你不用再擔心對這些例項怎麼實現快取了吧。

@Singleton
public class SingletonClass {  
}

@Reusable

這是一個新的很酷的功能。單例雖然很好,但有些時候例項可能有些太大,一直放在記憶體,又不能回收,暫時可能程式也用不到,怎麼都感覺有些浪費。很多情況下,我們並沒有那麼嚴格的要求需要唯一的一個例項,能重用就重用,沒有重新例項化一個就行。這就是@Reusable的使用場景,假如已有一個生成的例項,重用它就行,不行重新例項化,不需要保證。

@Reusable
public class ReusableClass {  
}

Lazy

Lazy使用的地方和前兩者有些不同。@Singleton@Reusable一般用在provides或型別定義的地方,但Lazy則是用在使用時,它的使用效果和最開始講到的SupplierMemoize類似。

@Inject
Lazy<SQLiteOpenHelper> lazySQLiteOpenHelper;  

這裡不會先生成SQLiteOpenHelper例項,直到你開始呼叫lazySQLiteOpenHelper.get()。而一旦第一次例項化結束,以後的呼叫都會返回第一次的結果。

Observable

在使用app的過程中,很多資料需要從伺服器端獲取。在我們app裡,每天會為使用者提供一些訂製化內容,這些內容短期內不會改變,每次從伺服器端去取太過耗時,但放到資料庫或檔案這些持久化儲存裡似乎不太必要。綜合考慮後,似乎記憶體快取是個不錯的選擇。

於是這個快取需要提供以下功能,首先,它是個快取,其次,它的結構需要很簡單,因為很多地方需要用到,再次,它得執行緒安全。

後來我們的實現方案很簡單,利用RetrofitObservable提供的一些方法。

  private static final long EXPIRE_MS = 5 * 60 * 1000;
  private Pair<Long, Observable<Content>> cache;

  public synchronized Observable<Content> getDailyContent() {
    if (cache == null || cache.first + EXPIRE_MS < System.currentTimeMillis()) {
      cache = Pair.create(System.currentTimeMillis(), serverApi.getContent());
    }

    return cache.second;
  }

這個方法的本質是利用Retrofit返回的Observable物件,然後Observable會提供一個類似快取的cache方法,這樣在subscribe之前,這個網路請求不會被髮出,但一旦有了結果,後來的呼叫者都會得到同樣的結果。

注意

快取雖好,用起來很快捷方便,但在使用過程中,大家一定要注意資料更新和執行緒安全,不要出現髒資料。