Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android room query is empty when using Flow

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
like image 441
elya5 Avatar asked Sep 05 '25 15:09

elya5


1 Answers

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")
        }
    }
}
like image 145
aminography Avatar answered Sep 10 '25 11:09

aminography