Daniel
Daniel

Reputation: 21

Performing multiple data insertions into a room with a single button onClick

I am trying to insert data into three different tables when a button is pressed by the user and onClick is called. What I have observed is that all three insertions never work, but if I remove any of the insertions then the other two will work. For example, leaving all three insertions in means that systemNotification object is not inserted into the database.

Currently my button's onClick calls three functions in the view model:

Button(
  // other button properties
   onClick = {
      viewModel.saveRoute(route)
      viewModel.saveRouteNotifications(routeNotificationList)
      viewModel.saveSystemNotifications(systemNotificationList)
      navigateUp.invoke()  // go back up to the previous page
   }
)

These are the three functions in the page's viewModel:

fun saveRoute(route: Route){
    viewModelScope.launch {
            repository.insertRoute(route)
    }
}

fun saveRouteNotifications(routeNotificationList: List<RouteNotification>){
    viewModelScope.launch {
            repository.insertRouteNotificationList(routeNotificationList)
    }
}

fun saveSystemNotifications(systemNotificationList: List<SystemNotification>){
    viewModelScope.launch {
            repository.insertSystemNotificationList(systemNotificationList)
    }
}

These are in the dao:

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertRoute(route: Route)

    @Insert
    suspend fun insertRouteNotificationList(routeNotificationList: List<RouteNotification>)

    @Insert
    suspend fun insertSystemNotificationList(systemNotificationList: List<SystemNotification>)

As I mentioned earlier on, only two of these three insertions ever fully fun. For example, removing viewModel.saveRoute(route) from the button lets the systemNotificationList insert, but leaving the route insertion prevents the systemNotificationList from inserting. I have verified this by using the database inspector in Android Studio to check the state of each table after the button is pressed.

I have tried wrapping the three viewModel calls in a coroutineScope.launch {...} in hope that it would ensure all three insertions finished before exiting off the page. I have also tried combining all three functions in the viewModel so that all calls to the repository and dao sit within one viewModelScope.launch { ... }, but this only let the first insertion happen.

Upvotes: 1

Views: 67

Answers (1)

Daniel
Daniel

Reputation: 21

The solution was to stop performing all database insertions on the main thread. I did not realize was that using viewModelScope.launch { ... } defaults to the main thread. What I am assuming was happening was I was smashing the main thread with insertions and part way through the third insertion it would pop the stack back up to the previous page and destroy the processing viewModel function (or something along those lines anyway).

I stumbled across this answer to a different problem, which I applied to my problem and it worked! To be completely transparent, I made the following code changes on my three viewModel functions so they each ran on their own thread:

fun saveRoute(route: Route){
    //changed from viewModelScope.launch {
    CoroutineScope(Dispatchers.IO).launch {  
            repository.insertRoute(route)
    }
}

fun saveRouteNotifications(routeNotificationList: List<RouteNotification>){
    CoroutineScope(Dispatchers.IO).launch {
            repository.insertRouteNotificationList(routeNotificationList)
    }
}

fun saveSystemNotifications(systemNotificationList: List<SystemNotification>){
    CoroutineScope(Dispatchers.IO).launch {
            repository.insertSystemNotificationList(systemNotificationList)
    }
}

Upvotes: 1

Related Questions