Henrique Tavolaro
Henrique Tavolaro

Reputation: 571

Why is it trying to access the database on the main thread?

I am getting this error while trying to display Room data in a LazyColumn in my project.

Cannot access database on the main thread since it may potentially lock the UI for a long period of time

I don't know why it is trying to access the database since I'm getting it with a ViewModelScope. Bellow is my MainActivity code and the ViewModel

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val viewModel: UserViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

            val users = viewModel.userList.value

LazyColumn(modifier = Modifier.fillMaxWidth()) {
                            items(users){data->
                                MyCard(data)
                            }
@HiltViewModel
class UserViewModel @Inject constructor(
    private val repository: MainRepository
) : ViewModel() {
val userList: MutableState<List<User>> = mutableStateOf(listOf())

    init {
        viewModelScope.launch {
            try {
                val result: List<User> = repository.getAllUsers()
                userList.value = result
            } catch (e: Exception) {
                Log.e("SSS", "${e.message.toString()}; ${e.stackTrace}")
            }
        }
    }

Upvotes: 0

Views: 1042

Answers (2)

Uuu Uuu
Uuu Uuu

Reputation: 1282

When launch { ... } is used without parameters, it inherits the context (and thus dispatcher) from the CoroutineScope it is being launched from.

Use IO thread to execute your code

    viewModelScope.launch(Dispatchers.IO) {
      try {
        val result: List<User> = repository.getAllUsers()
        userList.postValue(result)
      } catch (e: Exception) {
        Log.e("SSS", "${e.message.toString()}; ${e.stackTrace}")
      }
    }

Upvotes: 1

Tenfour04
Tenfour04

Reputation: 93511

Assuming you are following the pattern of your repository passing through functions from the DAO, you should mark this function in your DAO as a suspend function. This will cause it to automatically use a background thread. Then mark your corresponding repository function suspend so it can call the other suspend function.

Then in your coroutine, since getAllUsers() is a proper suspend function that internally handles proper use of background threads, there is nothing more you need to change.

The reason it gives you the warning is that by default, the viewModelScope runs on the main thread. It is up to you to wrap blocking calls in withContext(Dispatchers.IO) to run them in a background thread. But if you use suspend functions from the DAO, you don't have to worry about that because the function isn't blocking.

Upvotes: 1

Related Questions