'Periodically query a database and Flow the result in Android

In Android I'd like to 'poll' i.e. send GET requests to a webserver every 10secs, write the data-received into a Room Database, and Flow the database-contents to a UI.

I'm stuck trying to get things to loop every 10 seconds.

Following some examples online, I'm trying to define a channelFlow function inside a Repository. I want it to loop, flowing data periodically. It seems to stop at 'collect' inside the 'try' block however (I've independently checked that my Retrofit, Room etc. are all set up correctly, so I'm pretty certain the problem lies in my understanding of 'flow')

class Repository ...

fun poll() : Flow<List<myObj>>{
                return channelFlow {
                    var data: List<myObj>
                    while (true) { 
                        try {
                            data = mRetrofitApi.getData()     // get List<myObj> by Retrofit
                            dao.storeInDb(data)               // Store in Room Db
                            dao.readDb().collect{send(it)}  // flow the Db contents 
                            Log.d(TAG, "THIS LINE DOESN'T HAPPEN!?")
                        } catch (e:Exception){
                            Log.d(TAG, "Fail")
                        }
                        delay(10000L)  // delay 10secs and loop,
                    }
                }
            }
     

My Room database functions (dao's above) look like this (readDb() returns a flow)

@Dao
interface myDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun storeInDb(objList : List<myObj>)

    @Query("SELECT * FROM my_table order by date DESC")  
    fun readDb() : Flow<List<myObj>>

In my view model I'm attempting to invoke poll(), and forward the flow to my UI as a StateFlow (which I understand is the official Android recommendation)

class MyViewModel @Inject internal constructor(
    myRepository: Repository) : ViewModel() {

    val data = myRepository.poll().stateIn(viewModelScope,SharingStarted.Lazily, null)}

Finally, my UI tries to collect the flow data (and send it to a list adapter)

     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
                super.onViewCreated(view, 
         savedInstanceState) 
...
     viewLifecycleOwner.lifecycleScope.launch {
                        repeatOnLifecycle(Lifecycle.State.STARTED) {
                            launch {
                                myViewModel.data.collect { data ->
                                    dataAdapter.differ.submitList(data)
                                }
                            }
                        }

   

A curious observation is that when I first start my app, a single retrofit GET happens, and my UI does receive a single flow result. Things don't loop however, and the Poll() Log.d(TAG, "THIS LINE DOESN'T HAPPEN!?") line doesn't seem to happen (even once).

What am I doing wrong?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source