【问题标题】:How to pre-populate the room database with some data under hilt viewModel?如何在 hilt viewModel 下使用一些数据预先填充房间数据库?
【发布时间】:2021-10-18 19:35:23
【问题描述】:

我用hilt写了一个数据库创建方法,我想在数据库中预填充一些数据,但是我应该如何在AppModule中写一个RoomDatabase.Callback()?

@Database(entities = [Puzzle::class], version = 1, exportSchema = false)
abstract class PuzzleDatabase : RoomDatabase() {
    abstract fun getPuzzleDao() : PuzzleDao
}

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Singleton
    @Provides
    fun PuzzleDatabase(
        @ApplicationContext app: Context,
        scope: CoroutineScope
    ) = Room.databaseBuilder(
        app,
        PuzzleDatabase::class.java,
        "puzzle_database"
    ).build()

    @Singleton
    @Provides
    fun getDao(db: PuzzleDatabase) = db.getPuzzleDao()
}

使用 viewModel 创建 RoomDatabase.Callback() 而不使用 hilt 看起来像这样

@Database(
    entities = [Puzzle::class], version = 1
)
abstract class PuzzleDatabase : RoomDatabase() {
    abstract fun puzzleDao(): PuzzleDao

    private class PuzzleDataBaseCallBack(
        private val scope: CoroutineScope
    ): RoomDatabase.Callback() {
        override fun onCreate(db: SupportSQLiteDatabase) {
            super.onCreate(db)
            INSTANCE?.let { database ->
                scope.launch {
                    val puzzleDao = database.puzzleDao()
                    puzzleDao.insert(Puzzle(0, 9L, 5L, Puzzles.TWO))
                }
            }
        }
    }

    companion object {

        @Volatile
        private var INSTANCE: PuzzleDatabase? = null

        fun getDatabase(
            context: Context,
            scope: CoroutineScope
        ): PuzzleDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    PuzzleDatabase::class.java,
                    "puzzle_database"
                )
                    .addCallback(PuzzleDataBaseCallBack(scope))
                    .build()
                INSTANCE = instance
                instance
            }
        }
    }
}

但是在我的 AppModule 中,PuzzleDataBase() 有 @Singleton @Provides 注解,我应该如何正确创建 PuzzleDataBaseCallBack?

【问题讨论】:

    标签: android sqlite android-room android-jetpack-compose dagger-hilt


    【解决方案1】:

    我试着用之前的思路写了,大致上,成功了,但是不知道有没有不对的地方,如有不对请告诉我!

    @Database(entities = [Puzzle::class], version = 1, exportSchema = false)
    abstract class PuzzleDatabase : RoomDatabase() {
        abstract fun getPuzzleDao() : PuzzleDao
    }
    
    @Module
    @InstallIn(SingletonComponent::class)
    object AppModule {
    
        @Volatile
        private var INSTANCE: PuzzleDatabase? = null
    
        private class PuzzleDatabaseCallback(
            private val scope: CoroutineScope
        ) : RoomDatabase.Callback() {
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                INSTANCE?.let { /*database ->*/
                    scope.launch {
                        // you can pre-populate some data here
                        // database.getPuzzleDao().insert(Puzzle(0, 90000L, 2L, Puzzles.TWO))
                    }
                }
            }
        }
    
        @Singleton
        @Provides
        fun puzzleDataBase(
            @ApplicationContext app: Context
        ) : PuzzleDatabase {
            return INSTANCE ?: synchronized(this) {
                val scope = CoroutineScope(Dispatchers.IO)
                val instance = Room.databaseBuilder(
                    app,
                    PuzzleDatabase::class.java,
                    "puzzle_database"
                )   .addCallback(PuzzleDatabaseCallback(scope))
                    .build()
                    .also { INSTANCE = it }
                instance
            }
        }
    
        @Singleton
        @Provides
        fun getDao(db: PuzzleDatabase) = db.getPuzzleDao()
    
    }
    

    repository.kt

    class PuzzleRepository @Inject constructor (
        val puzzleDao: PuzzleDao
    ) {
        val all = puzzleDao.getAll()
    }
    

    【讨论】:

      【解决方案2】:

      您可以尝试使用以下代码:

      @Database(entities = [Puzzle::class], version = 1, exportSchema = false)
      abstract class PuzzleDatabase : RoomDatabase() {
      abstract fun getPuzzleDao() : PuzzleDao
      
      companion object {
          @Volatile
          private var instance: PuzzleDatabase ? = null
      
          fun getInstance(
              context: Context,
              scope: CoroutineScope
          ): PuzzleDatabase {
              return instance ?: synchronized(this) {
                  instance ?: buildDatabase(context).also { instance = it }
              }
          }
      
          private fun buildDatabase(context: Context): PuzzleDatabase {
              return Room.databaseBuilder(context, PuzzleDatabase ::class.java, "puzzleapp.db")
                  .addCallback(object : RoomDatabase.Callback() {
                      override fun onCreate(db: SupportSQLiteDatabase) {
                          super.onCreate(db)
                  // moving to a new thread
                  ioThread {
                      getInstance(context).dataDao()
                                          .insert(PREPOPULATE_DATA)
                      }
                  })
                  .build()
          }
      }
      }
      

      在我的情况下是:

      @Database(entities = [BeerItem::class], version = 2, exportSchema = false)
      abstract class BeerDatabase : RoomDatabase() {
          abstract fun beerDao(): BeerDao
      
          companion object {
              @Volatile
              private var instance: BeerDatabase? = null
      
              fun getInstance(
                  context: Context,
                  scope: CoroutineScope
              ): BeerDatabase {
                  return instance ?: synchronized(this) {
                      instance ?: buildDatabase(context).also { instance = it }
                  }
              }
      
              private fun buildDatabase(context: Context): BeerDatabase {
                  return Room.databaseBuilder(context, BeerDatabase::class.java, "beerapp.db")
                      .addCallback(object : RoomDatabase.Callback() {
                          override fun onCreate(db: SupportSQLiteDatabase) {
                              super.onCreate(db)
                              val request = OneTimeWorkRequestBuilder<DatabaseWorker>().build()
                              WorkManager.getInstance(context).enqueue(request)
                          }
                      })
                      .build()
              }
          }
      }
      

      ##而 DatabaseWorker 是:

      class DatabaseWorker(
          context: Context,
          workerParams: WorkerParameters
      ) : CoroutineWorker(context, workerParams) {
          
          override suspend fun doWork(): Result = coroutineScope {
              withContext(Dispatchers.IO) {
                  try {
                      @Suppress("BlockingMethodInNonBlockingContext")
                      applicationContext.assets.open(DATA_FILENAME).use { inputStream ->
                          JsonReader.of(Okio.buffer(Okio.source(inputStream))).use { jsonReader ->
                              val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
                              val listType =
                                  Types.newParameterizedType(List::class.java, BeerItem::class.java)
                              val adapter: JsonAdapter<List<BeerItem>> = moshi.adapter(listType)
                              val list = adapter.fromJson(jsonReader)
      
                              BeerDatabase.getInstance(
                                  applicationContext,
                                  CheersApp.instance.applicationScope
                              ).beerDao().insertBeers(list!!)
                              Result.success()
                          }
                      }
                  } catch (e: Exception) {
                      Timber.e(e, "Error seeding database")
                      Result.failure()
                  }
              }
          }
      }
      

      您可以在这里找到所有代码:https://github.com/ArcaDone/PunkAPI

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-11
        • 2020-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-18
        相关资源
        最近更新 更多