如何將Android Room封裝成一個類似Redis的快取資料庫的效果。
Android Room封裝快取。如果你還在用SharedPreferences,試試使用這種方式?
Android Room是一個非常棒的資料庫框架,提供了明確地Dao層來運算元據庫(越來越像spring data jpa啦),這裡我來告訴你如何使用Room封裝出一個類似Redis的使用方式(寫過後端的童鞋應該懂)。主要目標,把它弄成K/V資料庫的效果。
1. 引入
allprojects {
repositories {
mavenCentral()
google()
jcenter()
maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" }
}
}
dependencies {
implementation 'android.arch.persistence.room:runtime:1.0.0'
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
}
複製程式碼
2. 定義實體
快取表
@Entity(tableName = "cache")
public class CacheEntity {
@PrimaryKey(autoGenerate = true)
public int id;
public String key;
public String value;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
複製程式碼
3. 封裝初始化操作
DatabaseConfig.class
@Database(entities = {CacheEntity.class}, version = 1, exportSchema = false)
public abstract class DatabaseConfig extends RoomDatabase {
public abstract CacheDao mCacheDao();
}
複製程式碼
DatabaseInitialize.class
public class DatabaseInitialize {
private static DatabaseConfig databaseConfig;
public DatabaseInitialize(){}
public static void init(Context context) {
// 生成資料庫例項
databaseConfig = Room
.databaseBuilder(context.getApplicationContext(), DatabaseConfig.class, "huiminyougou")
.allowMainThreadQueries() // 允許主執行緒中查詢
.build();
}
static DatabaseConfig getDatabaseConfig() {
if (databaseConfig == null) {
throw new NullPointerException("DatabaseInitialize.init(context) has not call, remember call this function in your Application.class");
}
return databaseConfig;
}
}
複製程式碼
DatabaseSession.class
public final class DatabaseSession {
private DatabaseSession(){}
public static DatabaseConfig get() {
return DatabaseInitialize.getDatabaseConfig();
}
}
複製程式碼
4. dao層
@Dao
public interface CacheDao {
@Insert
void insertCaches(CacheEntity... cacheEntities);
@Update
void updateCaches(CacheEntity... cacheEntities);
@Query("SELECT * FROM cache WHERE `key` = :key LIMIT 0,1")
CacheEntity findByKey(String key);
@Delete
void deleteCaches(CacheEntity... cacheEntities);
@Query("SELECT * FROM cache")
CacheEntity[] findAll();
}
複製程式碼
5. service(utils)層
public final class CacheService {
private CacheService() {
}
private static CacheDao getRepository() {
return DatabaseSession.get().mCacheDao();
}
/**
* 設定快取
*
* @param key
* @param value
*/
public static void set(String key, String value) {
CacheEntity cacheEntity;
cacheEntity = getRepository().findByKey(key);
if (cacheEntity == null) {
cacheEntity = new CacheEntity();
cacheEntity.setKey(key);
cacheEntity.setValue(value);
getRepository().insertCaches(cacheEntity);
} else {
cacheEntity.setValue(value);
getRepository().updateCaches(cacheEntity);
}
}
/**
* 設定快取
*
* @param key
* @param value
*/
public static void set(String key, Object value) {
CacheEntity cacheEntity = getRepository().findByKey(key);
if (cacheEntity == null) {
cacheEntity = new CacheEntity();
cacheEntity.setKey(key);
String jsonValue = GsonHelper.toJson(value);
cacheEntity.setValue(jsonValue);
getRepository().insertCaches(cacheEntity);
} else {
String jsonValue = GsonHelper.toJson(value);
cacheEntity.setValue(jsonValue);
getRepository().updateCaches(cacheEntity);
}
}
/**
* 獲取快取
*
* @param key
* @return
*/
public static String get(String key) {
CacheEntity cacheEntity = getRepository().findByKey(key);
if (cacheEntity == null) {
return null;
}
return cacheEntity.getValue();
}
/**
* 獲取快取物件
*
* @param key
* @param classOfT
* @param <T>
* @return
*/
public static <T> T get(String key, Class<T> classOfT) {
CacheEntity cacheEntity = getRepository().findByKey(key);
if (cacheEntity == null) {
return null;
}
String jsonValue = cacheEntity.getValue();
return GsonHelper.toObject(jsonValue, classOfT);
}
/**
* 刪除快取
*
* @param key
*/
public static void delete(String key) {
CacheEntity cacheEntity = getRepository().findByKey(key);
if (cacheEntity != null) {
getRepository().deleteCaches(cacheEntity);
}
}
/**
* 刪除全部快取
*/
public static void clearAll() {
CacheEntity[] cacheEntities = getRepository().findAll();
if (cacheEntities != null && cacheEntities.length != 0) {
getRepository().deleteCaches(cacheEntities);
}
}
}
複製程式碼
GsonHelper.class
public class GsonHelper {
private GsonHelper() {
// no instance
}
private static Gson gson = new GsonBuilder().disableHtmlEscaping().create();
public static String toJson(Object o) {
return gson.toJson(o);
}
public static <T> T toObject(String json, Class<T> classOfT) {
return gson.fromJson(json, classOfT);
}
public static <T> List<T> toList(String json, Class<? extends T[]> clazz) {
T[] array = gson.fromJson(json, clazz);
return Arrays.asList(array);
}
}
複製程式碼
6. 初始化操作
@Override
public void onCreate() {
super.onCreate();
DatabaseInitialize.init(this);
}
複製程式碼
7. 使用方式
這裡以一個網路請求獲取首頁資料為例: 使用的是retrofit+rxjava,在請求成功後,將響應實體存入資料庫中。
mGoodsRequestService.goodsShowIndex(lng, lat)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseHttpObserver<GoodsIndex>() {
@Override
public void onSubscribe(Disposable d) {
mView.onRequestSubscribe(d);
}
@Override
public void onSuccess(String msg, GoodsIndex data) {
CacheService.set(Constant.CacheKey.HOME_INDEX, data);
mView.onGoodsIndexRespond(data);
mView.onRequestComplete();
}
@Override
public void onFailure(String msg) {
}
@Override
public void onNetworkError(Throwable e) {
mView.onRequestError(e);
}
});
複製程式碼
在頁面啟動伊始,從資料庫中拿到快取資料:
GoodsIndex goodsIndex = CacheService.get(Constant.CacheKey.HOME_INDEX, GoodsIndex.class);
if (goodsIndex != null) {
mView.onGoodsIndexRespond(goodsIndex);
}
複製程式碼
8. 末
這裡的service層處理得並不是很好,但是Android上沒有類似@Autowired這樣的註解,網路很多關於Dagger2的文章也是雲裡霧裡,後面思考一下如何用AOP + Dagger2 封裝一個類似的@Autowired出來。有哪位大佬可以指點一下^_^