I am confused about using Flow
with Room
for database access. I want to be able to observe a table for changes but also access it directly.
However, when using a query that returns a Flow
, the result always seems to be null
although the table is not empty. A query that returns a List
directly, seems to work.
Can someone explain the difference or show me which part of the documentation I might have missed?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db_button.setOnClickListener {
val user_dao = UserDatabase.getInstance(this).userDatabaseDao
lifecycleScope.launch {
user_dao.insertState(State(step=4))
val states = user_dao.getAllState().asLiveData().value
if (states == null || states.isEmpty()) {
println("null")
} else {
val s = states.first().step
println("step $s")
}
val direct = user_dao.getStatesDirect().first().step
println("direct step $direct")
}
}
}
}
@Entity(tableName = "state")
data class State(
@PrimaryKey(autoGenerate = true)
var id: Int = 0,
@ColumnInfo(name = "step")
var step: Int = 0
)
@Dao
interface UserDatabaseDao {
@Insert
suspend fun insertState(state: State)
@Query("SELECT * FROM state")
fun getAllState(): Flow<List<State>>
@Query("SELECT * FROM state")
suspend fun getStatesDirect(): List<State>
}
Output:
I/System.out: null
I/System.out: direct step 1
In Room
, we use Flow
or LiveData
to observe changes in a query result. So Room
queries the db
asynchronously and when you are trying to retrieve the value immediately, it is highly probable to get null
.
As a result, if you want to get the value immediately, you shouldn't use Flow
as the return type of a room query function, just like what you did on getStatesDirect(): List<State>
. On the other hand, if you want to observe data changes, you should use the collect terminal function on the Flow
to receive its emissions:
lifecycleScope.launch {
user_dao.insertState(State(step=4))
val direct = user_dao.getStatesDirect().first().step
println("direct step $direct")
}
lifecycleScope.launch {
user_dao.getAllState().collect { states ->
if (states == null || states.isEmpty()) {
println("null")
} else {
val s = states.first().step
println("step $s")
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With