androidkotlinandroid-roomkotlin-coroutinesandroid-threading

Android Room - Cannot access database on the main thread


I'm getting the "Cannot access database on the main thread since it may potentially lock the UI for a long period of time." error, but from what I understand I'm launching a new coroutine to insert the data to the database. What am I doing wrong?

RadioActivity:

        val finishButton : Button = findViewById(R.id.radioFinishButton)
        finishButton.setOnClickListener {
            val radioName = findViewById<EditText>(R.id.radioName)
            val radioUri = findViewById<EditText>(R.id.radioUri)
            val replyIntent = Intent()

            when {
                TextUtils.isEmpty(radioName.text) -> radioName.error = "Radio name is required!"
                TextUtils.isEmpty(radioUri.text) -> radioUri.error = "Radio URL is required!"
                else -> {
                    replyIntent.putExtra(EXTRA_REPLY_NAME, radioName.text.toString())
                    replyIntent.putExtra(EXTRA_REPLY_URI, radioUri.text.toString())
                    setResult(Activity.RESULT_OK, replyIntent)
                    finish()
                }
            }
        }

RadioFragment:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val getResult = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ){
            var name = ""
            var uri = ""
            if(it.resultCode == Activity.RESULT_OK){
                it.data?.getStringExtra(RadioActivity.EXTRA_REPLY_NAME)?.let{ reply ->
                    name = reply
                }
                it.data?.getStringExtra(RadioActivity.EXTRA_REPLY_URI)?.let{ reply ->
                    uri = reply
                }
                Toast.makeText(context, "Name = ${name}, uri = ${uri}", Toast.LENGTH_LONG).show()
                val radio = Radio(5, name, uri)
                radioViewModel.insert(radio)
            }else{
                Toast.makeText(context, "Error while saving", Toast.LENGTH_LONG).show()
            }
        }

        val recyclerView = view.findViewById<RecyclerView>(R.id.radioRecyclerView)
        val adapter = RadioListAdapter()
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(context)

        radioViewModel.radioList.observe(viewLifecycleOwner) {
            it.let{
                adapter.submitList(it)
            }
        }
    }

RadioRepository:

val radioList: Flow<List<Radio>> = radioDao.getAll()
    @Suppress("RedundantSuspendModifier")
    @WorkerThread
    suspend fun insert(radio: Radio) {
        radioDao.insert(radio)
    }

RadioModel:

    fun insert(radio: Radio) = viewModelScope.launch {
        repository.insert(radio)
    }

Solution

  • Try to switch context in RadioRepository:

    suspend fun insert(radio: Radio) = withContext(Dispatchers.IO) {
        radioDao.insert(radio)
    }
    

    You are using @Suppress("RedundantSuspendModifier") annotation, which suppresses the RedundantSuspendModifier error. This error means your insert function is non suspend and will be running in thread, which invoked it.

    withContext(Dispatchers.IO) switches the context of coroutine, making insert function to run in background(worker) thread.