首页 > 解决方案 > 调用主线程后,房间数据库操作不会崩溃

问题描述

我用来对我的数据库Coroutines执行db操作Room我已经为 Coroutines 创建了一个帮助程序,如下所示

object Coroutines {

    fun main(work: suspend(() -> Unit)) = CoroutineScope(Dispatchers.Main).launch {
        work()
    }

    fun io(work: suspend(() -> Unit)) = CoroutineScope(Dispatchers.IO).launch {
        work()
    }
}

以下是我在主线程上调用插入操作的代码

class LocalListViewModel(private val localVideoRepository: LocalVideoRepository) : ViewModel() {

     val localVideos = MutableLiveData<ArrayList<LocalVideo?>?>()

     fun insertAllLocalVideo() {
          Coroutines.main {
               localVideoRepository.insertLocalVideo(localVideos.value)
          }
     }
}

class LocalVideoRepository(private val db: AppDatabase) {

    suspend fun insertLocalVideo(localVideos: ArrayList<LocalVideo?>?) =
        db.getLocalVideoDao().insertLocalVideos(localVideos)

   }

@Dao
interface LocalVideoDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertLocalVideos(localVideoList: ArrayList<LocalVideo?>?)
}

@Database(entities = [LocalVideo::class], version = 1)
abstract class AppDatabase : RoomDatabase() {

    abstract fun getLocalVideoDao(): LocalVideoDao

    companion object {

        @Volatile
        private var instance: AppDatabase? = null
        private val LOCK = Any()

        operator fun invoke(context: Context) = instance ?: synchronized(LOCK) {
            instance ?: buildDatabase(context).also { instance = it }
        }

        private fun buildDatabase(context: Context) = Room.databaseBuilder(
            context.applicationContext,
            AppDatabase::class.java,
            context.getString(R.string.psplayer_db)
        ).build()
    }
}

我不明白的是,即使在调用主线程之后Coroutines,数据也会成功插入,而不是崩溃?

标签: androidkotlinandroid-roomkotlin-coroutines

解决方案


要获得深入的答案,请查看CoroutinesRoom.execute帮助程序:

    suspend fun <R> execute(
        db: RoomDatabase,
        inTransaction: Boolean,
        callable: Callable<R>
    ): R {
        if (db.isOpen && db.inTransaction()) {
            return callable.call()
        }

        // Use the transaction dispatcher if we are on a transaction coroutine, otherwise
        // use the database dispatchers.
        val context = coroutineContext[TransactionElement]?.transactionDispatcher
            ?: if (inTransaction) db.transactionDispatcher else db.queryDispatcher
        return withContext(context) {
            callable.call()
        }
    }

除非它已经在事务中,否则它总是将实际查询的执行转移到 IO 优化的调度程序上。因此,无论调用上下文如何,suspend房间定义都不会在应用程序线程上执行。


推荐阅读