Flow is not collected from room after an update

66 views Asked by At

I am currently migrating an android application from XML, Databinding and Flow/LiveData to Compose, Flow/StateFlow.

In this application, I have a very simple Room database:

@Entity
data class User(@PrimaryKey var id: Int = 0, var name: String)
@Dao
interface UserDAO
{

  @Query("Select * from User where id = :userId")
  fun getUserFlow(userId: Int): Flow<User?>

  @Transaction
  @Insert(onConflict = OnConflictStrategy.REPLACE)
  suspend fun createNewUser(user: User)

  @Transaction
  @Update(onConflict = OnConflictStrategy.IGNORE)
  suspend fun updateUser(user: User)

}
@Database(
  entities = [User::class],
  version = 1,
  exportSchema = true
)
abstract class UserDatabase
  : RoomDatabase()
{

  abstract fun userDao(): UserDAO

}

From a ViewModel, I create, update and collect the data from the database:

class MainViewModel(application: Application)
  : AndroidViewModel(application)
{

  private val userDatabase by lazy { Room.databaseBuilder(application, UserDatabase::class.java, "user-data.db").build() }

  private val user = userDatabase.userDao().getUserFlow(0).stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)

  val name = user.map {
    it?.name ?: "no name"
  }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), "pouet")

  fun create()
  {
    viewModelScope.launch(Dispatchers.IO) {
      userDatabase.userDao().createNewUser(User(name = "Test"))
    }
  }

  fun update()
  {
    viewModelScope.launch(Dispatchers.IO) {
      user.value?.name = UUID.randomUUID().toString()

      user.value?.let {
        userDatabase.userDao().updateUser(it)
      }
    }
  }

}

And then I collect the StateFlow using collectAsStateWithLifecycle into the activity:

class MainActivity : ComponentActivity()
{

  private val model: MainViewModel by viewModels()

  override fun onCreate(savedInstanceState: Bundle?)
  {
    super.onCreate(savedInstanceState)
    setContent {
      MyApplicationTheme {
        val name = model.name.collectAsStateWithLifecycle()

        Column(modifier = Modifier.fillMaxSize()) {
          Button(
            onClick = { model.create() }) {
            Text("Create")
           }
          Button(
            onClick = { model.update() }) {
            Text("Update")
          }
          Text(
            text = "Hello ${name.value}!",
          )
        }
      }
    }
  }
}

When I click on the create button, the user is inserted in the database but the UI is not updated.

When I click on the update button, the user name is updated correctly in the database but the UI is not updated.

Using Android Studio, if I change directly the user name in the database, the UI is correctly updated.

I do not understand why the StateFlow is correctly collected when I update manually the database using Android Studio but it does not work when the database is updated using the code.

Thank you for your help!

0

There are 0 answers