기존의 내부 테스트용을 상용으로 개발하는일이 생겼는데 Room에서 문제가 일어났습니다.
fun getDatabase(context: Context): TracerRoomDatabase {
return Room.databaseBuilder(
context.applicationContext,
TracerRoomDatabase::class.java,
"test.db"
).addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Log.d("test", "onCreate")
Executors.newSingleThreadExecutor().execute {
runBlocking {
insertDB(getDatabase(context).serverInfoDao())
}
}
}
}).build()
}
addCallback()
함수의 OnCreate()
에서는 데이터베이스가 처음 호출될떄(Query가 처음 실행되거나 @Dao 메서드가 처음호출될때) 호출하게 되는데요.
저희는 이러한 메서드 안에서 DB를 DB를 구축하는 작업을 하고 있습니다.
하지만 이러한 OnCreate()가 호출되지 않을대가 있었습니다.
그래서 임시방편으로 MainViewModel이 호출될때 DB를 쌓아버렸는데요.
init {
viewModelScope.launch {
TracerRoomDatabase.insertDB(tracerRoomDatabase.serverInfoDao())
}
}
알고보니 AndroidManifast.xml의 android:allowBackup="true"
가 문제였습니다.
Backup이 이루어졌기 때문에 OnCreate가 호출되지 않았던 것이죠.
이제 추가적으로 볼껀 addCallback에서 Dao를 호출하는것입니다.
Query를 호출하려면 Dao를 호출해야되는데요.
당연히 Dao를 호출하려면 순환때문에 Inject를 할수가 없는데요.
fun getDatabase(context: Context): TracerRoomDatabase {
return Room.databaseBuilder(
context.applicationContext,
TracerRoomDatabase::class.java,
"테스트.DB"
).addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Log.d("TracerRoomDatabase", "onCreate")
Executors.newSingleThreadExecutor().execute {
runBlocking {
insertDB(getDatabase(context).serverInfoDao())
}
}
}
}).build()
}
DataBase -> Dao순으로 만들어지기 때문에 DataBase에서 DAO를 주입받을수 없는것이죠.
그래서 주입을 최대한 Lazy하게끔 만드는 방법이 필요한데요.
사용할수 있는 방법이 바로 Provider와 Lazy입니다.
이 클래스는 정수에 대한 Provider를 주입합니다.
Provider.get() 3번 호출하고 각 결과를 인쇄합니다.
final class ProviderCounter {
@Inject Provider<Integer> provider;
void print() {
System.out.println("printing...");
System.out.println(provider.get());
System.out.println(provider.get());
System.out.println(provider.get());
}
}
ProviderCounter 를 삽입하고 print() 호출하면 Provider.get() 사용될 때마다 새 값이 계산되는 것을 볼 수 있습니다.
printing...
computing...
100
computing...
101
computing...
102
이 클래스는 정수에 대해 Lazy 주입합니다. 위의 공급자와 마찬가지로 Lazy.get() 3번 호출하고 각 결과를 인쇄합니다.
final class LazyCounter {
@Inject Lazy<Integer> lazy;
void print() {
System.out.println("printing...");
System.out.println(lazy.get());
System.out.println(lazy.get());
System.out.println(lazy.get());
}
}
LazyCounter 를 삽입하고 print() 호출하면 새 값이 필요하기 직전에 계산된다는 것을 알 수 있습니다. 이후의 모든 사용에 대해 동일한 값이 반환됩니다.
printing...
computing...
100
100
100
Provider는 호출할때마다 재주입을 하게되며, Lazy는 객체가 호출될때까지 주입시점을 최대한 미루게 됩니다.
저는 Lazy를 통해 주입을 받았습니다.
@Singleton
@Provides
fun provideAppDatabase(@ApplicationContext context: Context, serverInfoDao: Lazy<ServerInfoDao>): TracerRoomDatabase {
return Room.databaseBuilder(
context.applicationContext,
TracerRoomDatabase::class.java,
"테스트.db"
).addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Log.d("TracerRoomDatabase", "onCreate")
Executors.newSingleThreadExecutor().execute {
runBlocking {
TracerRoomDatabase.insertDB(serverInfoDao.get())
}
}
}
}).build()
}
Why onCreate() of RoomDatabase.Callback() is not called?
Prepopulating Room Database with Hilt