在 Android 中,Room 爲 SQLite 提供了高效穩定的抽象層,簡化開發流程。RoomDatabase.java
是初始化數據庫的重要構建組件,通過它我們可以添加RoomDatabase#Callback
監聽,RoomDatabase#Callback
提供了以下回調接口:
/**
* Callback for {@link RoomDatabase}.
*/
public abstract static class Callback {
/**
* Called when the database is created for the first time. This is called after all the
* tables are created.
*
* @param db The database.
*/
public void onCreate(@NonNull SupportSQLiteDatabase db) {
}
/**
* Called when the database has been opened.
*
* @param db The database.
*/
public void onOpen(@NonNull SupportSQLiteDatabase db) {
}
/**
* Called after the database was destructively migrated
*
* @param db The database.
*/
public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db){
}
}
但是對於RoomDatabase#Callback
提供的回調接口有時很難滿足我們的開發需求,因爲它沒有將數據庫打開過程的完整生命週期事件暴露出來。我們更需要的是SupportSQLiteOpenHelper#Callback
開放的生命週期事件:
- onConfigure 在數據庫創建或打開之前回調,在這可以添加一些數據庫能力,如打開 WAL 日誌模式
- onCreate 數據庫首次創建時回調
- onUpgrade 數據庫版本低於請求版本時回調,進行升級處理
- onDowngrade 類似於 onUpgrade,數據庫版本高於請求版本時回調,進行降級處理
- onOpen 數據庫連接打開後回調
- onCorruption 在數據庫損壞時調用,默認刪除db及相關日誌文件
Room框架中SupportSQLiteOpenHelper#Callback
的實現類是RoomOpenHelper
,幸運的是這個 callback 被注入到SupportSQLiteOpenHelper.Configuration
中,並且 Room 允許我們使用SupportSQLiteOpenHelper.Configuration
來提供自定義的SupportSQLiteOpenHelper
。因此我們可以對FrameworkSQLiteOpenHelper
和RoomOpenHelper
進行一層代理並開放出想要的生命週期回調。
值得一提的是Room框架下,FrameworkSQLiteOpenHelper
使用SupportSQLiteOpenHelper#Callback
的onCorruption
方法來處理數據庫損壞的情況,而其處理策略是刪除db及其關聯的日誌文件。
OpenHelper(Context context, String name, final FrameworkSQLiteDatabase[] dbRef,
final Callback callback) {
super(context, name, null, callback.version,
new DatabaseErrorHandler() {
@Override
public void onCorruption(SQLiteDatabase dbObj) {
callback.onCorruption(getWrappedDb(dbRef, dbObj));
}
});
mCallback = callback;
mDbRef = dbRef;
}
很多時候這並不是我們想要的處理方式,通過代理RoomOpenHelper
,替換掉onCorruption
的默認實現方式,這樣就實現了自定義 DatabaseErrorHandler
。
下面給出具體的代碼示例展示如何進行代理:
// 自定義 SupportSQLiteOpenHelper.Factory
public class DecoratedOpenHelperFactory implements SupportSQLiteOpenHelper.Factory {
@NonNull
private final SupportSQLiteOpenHelper.Factory delegate;
@Nullable
private final SupportSQLiteOpenHelper.Callback customListener;
public DecoratedOpenHelperFactory(@NonNull SupportSQLiteOpenHelper.Factory factory, @Nullable SupportSQLiteOpenHelper.Callback customListener) {
this.delegate = factory;
this.customListener = customListener;
}
@Override
public SupportSQLiteOpenHelper create(@NonNull SupportSQLiteOpenHelper.Configuration configuration) {
final SupportSQLiteOpenHelper.Configuration sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context)
.name(configuration.name)
.callback(new DecoratedCallback(configuration.callback, customListener))
.build();
return delegate.create(sqliteConfig);
}
}
// 自定義 SupportSQLiteOpenHelper.Callback
public class DecoratedCallback extends SupportSQLiteOpenHelper.Callback {
@NonNull
private final SupportSQLiteOpenHelper.Callback delegate;
@Nullable
private final SupportSQLiteOpenHelper.Callback customListener;
public DecoratedCallback(@NonNull SupportSQLiteOpenHelper.Callback supportSqLiteOpenHelperCallback, @Nullable SupportSQLiteOpenHelper.Callback customListener) {
super(supportSqLiteOpenHelperCallback.version);
this.delegate = supportSqLiteOpenHelperCallback;
this.customListener = customListener;
}
@Override
public void onCreate(@Nullable SupportSQLiteDatabase db) {
delegate.onCreate(db);
Optional.ofNullable(customListener).ifPresent(customListener -> customListener.onCreate(db));
}
@Override
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
delegate.onUpgrade(db, oldVersion, newVersion);
Optional.ofNullable(customListener).ifPresent(customListener -> customListener.onUpgrade(db, oldVersion, newVersion));
}
@Override
public void onDowngrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
delegate.onDowngrade(db, oldVersion, newVersion);
Optional.ofNullable(customListener).ifPresent(customListener -> customListener.onDowngrade(db, oldVersion, newVersion));
}
@Override
public void onOpen(SupportSQLiteDatabase db) {
delegate.onOpen(db);
Optional.ofNullable(customListener).ifPresent(customListener -> customListener.onOpen(db));
}
@Override
public void onCorruption(SupportSQLiteDatabase db) {
Optional.ofNullable(customListener).ifPresent(customListener -> customListener.onCorruption(db));
}
}
最後,Room的構造使用如下:
Room.databaseBuilder(context, databaseName)
.openHelperFactory(new DecoratedOpenHelperFactory(
new FrameworkSQLiteOpenHelperFactory(), new SupportSQLiteOpenHelper.Callback() {
@Override
public void onCreate(SupportSQLiteDatabase db) {
}
@Override
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
}
// etc
}))
.build();