[삽질] Room addCallback 동작 안하는문제와 hilt에서 @dao를 CallBack에 전달하기

0

기존의 내부 테스트용을 상용으로 개발하는일이 생겼는데 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가 호출되지 않았던 것이죠.

hilt에서 @dao를 CallBack에 전달하기

이제 추가적으로 볼껀 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입니다.

1. Provider 주입

이 클래스는 정수에 대한 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

2. Lazy 주입

이 클래스는 정수에 대해 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

profile
쉽게 가르칠수 있도록 노력하자

0개의 댓글