'Method addObserver must be called on the main thread Exception, While inserting data to room database

I am trying to insert data into the room database using the kotlin coroutine. But I always get an exception java.lang.IllegalStateException: Method addObserver must be called on the main thread But I don't have an observer in this code, the insert call is called from launch with 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")
           }
     }
    
........
.......
}

}

what is wrong with this code? please help me



Solution 1:[1]

I was facing the same issue and I solved yhis way :

 private fun insertAllItemsInDb(data : List<PostResponse>){
         val listPost = data.map { it.toUI() }
         val scope = CoroutineScope(Job() + Dispatchers.Main)
         scope.launch {
             localViewModel.insertAllPosts(listPost)
         }
     }

ViewModel:

fun insertAllPosts(posts: List<PostItem>) {
        viewModelScope.launch {
            dbRepository.insertAllPosts(posts)
        }
}

Solution 2:[2]

Creating view model with:

val viewModel: MyViewModel by viewModels()

Will result in lazy creating. Creation of real object will be performed when you access your object for first time. This happens inside:

lifecycleScope.launch(Dispatchers.IO) {
     val res =  viewModel.demoInsert("test", Random.nextLong(500))
     Log.d(TAG, "onViewCreated: $res")
}

And since implementation of method viewModels<>() looks like this:

@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)

You are getting

Method addObserver must be called on the main thread

You should be able to fix this with something like this.

lifecycleScope.launch(Dispatchers.IO) {
     val res =  withContext(Dispatchers.Main + lifecycleScope.coroutineContext){}.demoInsert("test", Random.nextLong(500))
     Log.d(TAG, "onViewCreated: $res")
}

Solution 3:[3]

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))
                 
                 }
               
           }
           
     }
   
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dharman
Solution 2 Michal Zhradnk Nono3551
Solution 3 jagadishlakkurcom jagadishlakk