Android裡巧妙實現快取
為了快速查詢會被多次呼叫的資料,或者構建比較廢時的例項,我們一般使用快取的方法。快取的基本概念大體上差不多,這裡就不再重複,有興趣的可以檢視維基百科的介紹。
快取有很多的實現方式,技巧性還有坑都很多,今天我給大家介紹一些非通用的方法,可以巧妙地幫大家簡單實現一些記憶體快取。
Supplier
和Memoize
SQLite是Android裡常用的一種資料儲存方式,在訪問資料庫資料時需要通過SQLiteOpenHelper
。
一份好的資料庫連線程式碼應該能解決以下幾個問題: a) 構建例項比較費資源 b) 資料庫連線最好能複用 c) onUpdate
等方法在執行時不能和其他例項構成衝突。
這裡可以很簡單的這樣寫
Suppliers.memoize(new Supplier<SQLiteOpenHelper>() {
@Override
public SQLiteOpenHelper get() {
return new ...;
}
})
這段程式碼利用了Guava提供的一些輔助方法實現Supplier和Memoize和邏輯。顧名思義,Supplier
一般被用作factory
,generator
,builder
,closure
。Memoize
類似於快取這種概念,它一旦生成了一個例項,在以後的呼叫中都會返回同一例項,而且,執行緒安全。
這樣寫有幾個好處,一是需要時才去構建例項,並不會在一開始就去阻塞程式的執行,二是它很簡單的用memoize實現了快取,保證只有一個例項生成。
程式碼注入
Glow是程式碼注入的重度使用者,它使我們的程式碼更加結構化,清晰,簡單,同時還節省了不少的開發時間。
Dagger 2
是我們實現注入的刀具,有興趣的同學應該去網站多瞭解一下相關的內容。除了注入,它還有一些附贈功能,而這些恰巧能被我們用來實現快取,而且還很簡單,我們只需要額外用到幾個annotation
或介面而已。
@Singleton
相信大家對這個應該比較熟悉,這可是面試時的常問問題。簡單來說,它就是單例。因為所以,用了它你不用再擔心對這些例項怎麼實現快取了吧。
@Singleton
public class SingletonClass {
}
@Reusable
這是一個新的很酷的功能。單例雖然很好,但有些時候例項可能有些太大,一直放在記憶體,又不能回收,暫時可能程式也用不到,怎麼都感覺有些浪費。很多情況下,我們並沒有那麼嚴格的要求需要唯一的一個例項,能重用就重用,沒有重新例項化一個就行。這就是@Reusable
的使用場景,假如已有一個生成的例項,重用它就行,不行重新例項化,不需要保證。
@Reusable
public class ReusableClass {
}
Lazy
Lazy
使用的地方和前兩者有些不同。@Singleton
和@Reusable
一般用在provides
或型別定義的地方,但Lazy
則是用在使用時,它的使用效果和最開始講到的Supplier
和Memoize
類似。
@Inject
Lazy<SQLiteOpenHelper> lazySQLiteOpenHelper;
這裡不會先生成SQLiteOpenHelper
例項,直到你開始呼叫lazySQLiteOpenHelper.get()
。而一旦第一次例項化結束,以後的呼叫都會返回第一次的結果。
Observable
在使用app的過程中,很多資料需要從伺服器端獲取。在我們app裡,每天會為使用者提供一些訂製化內容,這些內容短期內不會改變,每次從伺服器端去取太過耗時,但放到資料庫或檔案這些持久化儲存裡似乎不太必要。綜合考慮後,似乎記憶體快取是個不錯的選擇。
於是這個快取需要提供以下功能,首先,它是個快取,其次,它的結構需要很簡單,因為很多地方需要用到,再次,它得執行緒安全。
後來我們的實現方案很簡單,利用Retrofit
和Observable
提供的一些方法。
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
之前,這個網路請求不會被髮出,但一旦有了結果,後來的呼叫者都會得到同樣的結果。
注意
快取雖好,用起來很快捷方便,但在使用過程中,大家一定要注意資料更新和執行緒安全,不要出現髒資料。