0

i'm facing hard times updating list of Orders in real time from firestore using stateflow !!

class RepositoryImp : Repository {
    private fun Query.snapshotFlow(): Flow<QuerySnapshot> = callbackFlow {
        val snapshott = addSnapshotListener { value, error ->
            if (error != null) {
                close()
                return@addSnapshotListener
            }
            if (value != null)
                trySend(value)
        }
        awaitClose {
            snapshott.remove()
        }
    }

    override fun getAllOrders() = flow<State<List<OrderModel>>> {

        emit(State.loading())

        val snapshot = ORDER_COLLECTION_REF.snapshotFlow()
            .mapNotNull { it.toObjects(OrderModel::class.java) }

        emit(State.success(snapshot)) // **HERE** !!!!!!

    }.catch {

        emit(State.failed(it.message.toString()))
    }.flowOn(Dispatchers.IO)
}

i'm receiving the error from // emit(State.success(snapshot)) that says :

Type mismatch: inferred type is Flow<(Mutable)List<OrderModel!>> but List< OrderModel> was expected

sealed class State <T> {

    class Loading <T> : State<T>()
    data class Success <T> (val data: T) : State <T>()
    data class Failed <T> (val message: String) : State <T>()

    companion object {

        fun <T> loading() = Loading <T>()
        fun <T> success(data: T) = Success(data)
        fun <T> failed(message: String) = Failed<T>(message)
    }
}

My fun to LoadOrders :

private suspend fun loadOrders() {

    viewModel.getAllOrders().collect { state ->
        when (state) {
            is State.Loading -> {
                showToast("Loading")
            }

            is State.Success -> {

                adapter.submitList(state.data)
            }

            is State.Failed -> showToast("Failed! ${state.message}")
        }
    }
}
  • I think that this [resource](https://medium.com/firebase-tips-tricks/how-to-make-a-clean-architecture-android-app-using-mvvm-firestore-and-jetpack-compose-abdb5e02a2d8) will defently help. Here is the corresponding [repo](https://github.com/alexmamo/FirestoreCleanArchitectureApp). – Alex Mamo Oct 26 '22 at 15:37

1 Answers1

1

Your snapshot variable is a Flow of lists, not a single List. If you want to just fetch the current list, you shouldn't use a flow for that. Instead use get().await().

override fun getAllOrders() = flow<State<List<OrderModel>>> {
    emit(State.loading())
    val snapshot = ORDER_COLLECTION_REF.get().await()
        .let { it.toObjects(OrderModel::class.java) }
    emit(State.success(snapshot))
}.catch {
    emit(State.failed(it.message.toString()))
}.flowOn(Dispatchers.IO)

The flowOn call is actually unnecessary because we aren't doing anything blocking. await() is a suspend function.


Based on comments discussion below, supposing we want to show a loading state only before the first item, then show a series of success states, and we want to show an error and stop emitting once there's an error, we could do:

override fun getAllOrders() = flow<State<List<OrderModel>>> {
    emit(State.loading())
    val snapshots = ORDER_COLLECTION_REF.snapshotFlow()
        .mapNotNull { State.success(it.toObjects(OrderModel::class.java)) }
    emitAll(snapshots)
}.catch {
    emit(State.failed(it.message.toString()))
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • thanks for ur reply man, but i need a way to get instant update with every change in the db – soufiane morsel Oct 24 '22 at 16:03
  • Then you need to rethink this wrapper flow that emits loading and success states. How do you want that to behave if it is continually always waiting for the next value? Only show the loading state before the first value, and then a series of success states? What should happen when there’s an error? Emit the error state and then stop emitting forever, or…? – Tenfour04 Oct 24 '22 at 16:08
  • i'm interrested in any approche u have , i just want a valid code for stateflow method for now – soufiane morsel Oct 24 '22 at 16:51
  • See update for an example. – Tenfour04 Oct 24 '22 at 16:56
  • works like a charm .. thank u so much man , hope u all the best !! – soufiane morsel Oct 24 '22 at 17:16