必须在主线程异常上调用方法 addObserver,同时将数据插入房间数据库
Method addObserver must be called on the main thread Exception, While inserting data to room database
我正在尝试使用 kotlin 协程将数据插入房间数据库。但我总是得到一个例外 java.lang.IllegalStateException: Method addObserver must be called on the main thread
但是我在这段代码中没有观察者,插入调用是从启动时使用 Dispatchers IO
调用的
DocumentDao.kt
@Dao
interface DocumentDao {
@Insert
suspend fun insertDocument(document: Document): Long
}
Repository.kt
class Repository@Inject constructor(val db: MyDB) {
suspend fun demoInsert(
uri: String,
albumId: Long
): Long {
val newDoc = Document(0, albumId, rawUri = uri)
return db.documentDao().insertDocument(newDoc)
}
}
MyViewModel.kt
@HiltViewModel
class MyViewModel@Inject constructor(val repo: Repository) : ViewModel() {
suspend fun demoInsert(
uri: String,
albumId: Long
): Long {
return repo.demoInsert(uri, albumId)
}
}
MyFrag.kt
@AndroidEntryPoint
class MyFrag: Fragment() {
val viewModel: MyViewModel by viewModels()
....
....
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.insert.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
val res = viewModel.demoInsert("test", Random.nextLong(500))
Log.d(TAG, "onViewCreated: $res")
}
}
........
.......
}
}
这段代码有什么问题?请帮助我
我不确定,但您可以使用 Main Dispatcher
在侦听器内部启动 coroutine
,然后在 DB 函数内部使用 withContext
来更改上下文。
正在创建视图模型:
val viewModel: MyViewModel by viewModels()
将导致延迟创建。当您第一次访问您的对象时,将执行真实对象的创建。这发生在里面:
lifecycleScope.launch(Dispatchers.IO) {
val res = viewModel.demoInsert("test", Random.nextLong(500))
Log.d(TAG, "onViewCreated: $res")
}
并且由于方法 viewModels<>() 的实现看起来像这样:
@MainThread
public inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
您正在获得
Method addObserver must be called on the main thread
你应该可以用类似的方法解决这个问题。
lifecycleScope.launch(Dispatchers.IO) {
val res = withContext(Dispatchers.Main + lifecycleScope.coroutineContext){}.demoInsert("test", Random.nextLong(500))
Log.d(TAG, "onViewCreated: $res")
}
我遇到了同样的问题,我是这样解决的:
private fun insertAllItemsInDb(data : List<PostResponse>){
val listPost = data.map { it.toUI() }
val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch {
localViewModel.insertAllPosts(listPost)
}
}
视图模型:
fun insertAllPosts(posts: List<PostItem>) {
viewModelScope.launch {
dbRepository.insertAllPosts(posts)
}
}
MyViewModel.kt
@HiltViewModel
class MyViewModel@Inject constructor(val repo: Repository) : ViewModel() {
suspend fun demoInsert(
uri: String,
albumId: Long
): Long {
viewModelScope.launch {
repo.demoInsert(uri, albumId)
}
}
}
MyFrag.kt
@AndroidEntryPoint
class MyFrag: Fragment() {
val viewModel: MyViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.insert.setOnClickListener {
lifecycleScope.launch(Dispatchers.Main) {
viewModel.demoInsert("test", Random.nextLong(500))
}
}
}
}
我正在尝试使用 kotlin 协程将数据插入房间数据库。但我总是得到一个例外 java.lang.IllegalStateException: Method addObserver must be called on the main thread
但是我在这段代码中没有观察者,插入调用是从启动时使用 Dispatchers IO
DocumentDao.kt
@Dao
interface DocumentDao {
@Insert
suspend fun insertDocument(document: Document): Long
}
Repository.kt
class Repository@Inject constructor(val db: MyDB) {
suspend fun demoInsert(
uri: String,
albumId: Long
): Long {
val newDoc = Document(0, albumId, rawUri = uri)
return db.documentDao().insertDocument(newDoc)
}
}
MyViewModel.kt
@HiltViewModel
class MyViewModel@Inject constructor(val repo: Repository) : ViewModel() {
suspend fun demoInsert(
uri: String,
albumId: Long
): Long {
return repo.demoInsert(uri, albumId)
}
}
MyFrag.kt
@AndroidEntryPoint
class MyFrag: Fragment() {
val viewModel: MyViewModel by viewModels()
....
....
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.insert.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
val res = viewModel.demoInsert("test", Random.nextLong(500))
Log.d(TAG, "onViewCreated: $res")
}
}
........
.......
}
}
这段代码有什么问题?请帮助我
我不确定,但您可以使用 Main Dispatcher
在侦听器内部启动 coroutine
,然后在 DB 函数内部使用 withContext
来更改上下文。
正在创建视图模型:
val viewModel: MyViewModel by viewModels()
将导致延迟创建。当您第一次访问您的对象时,将执行真实对象的创建。这发生在里面:
lifecycleScope.launch(Dispatchers.IO) {
val res = viewModel.demoInsert("test", Random.nextLong(500))
Log.d(TAG, "onViewCreated: $res")
}
并且由于方法 viewModels<>() 的实现看起来像这样:
@MainThread
public inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
您正在获得
Method addObserver must be called on the main thread
你应该可以用类似的方法解决这个问题。
lifecycleScope.launch(Dispatchers.IO) {
val res = withContext(Dispatchers.Main + lifecycleScope.coroutineContext){}.demoInsert("test", Random.nextLong(500))
Log.d(TAG, "onViewCreated: $res")
}
我遇到了同样的问题,我是这样解决的:
private fun insertAllItemsInDb(data : List<PostResponse>){
val listPost = data.map { it.toUI() }
val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch {
localViewModel.insertAllPosts(listPost)
}
}
视图模型:
fun insertAllPosts(posts: List<PostItem>) {
viewModelScope.launch {
dbRepository.insertAllPosts(posts)
}
}
MyViewModel.kt
@HiltViewModel
class MyViewModel@Inject constructor(val repo: Repository) : ViewModel() {
suspend fun demoInsert(
uri: String,
albumId: Long
): Long {
viewModelScope.launch {
repo.demoInsert(uri, albumId)
}
}
}
MyFrag.kt
@AndroidEntryPoint
class MyFrag: Fragment() {
val viewModel: MyViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.insert.setOnClickListener {
lifecycleScope.launch(Dispatchers.Main) {
viewModel.demoInsert("test", Random.nextLong(500))
}
}
}
}