# Emit Flow data from an event listener function

**URL:** <https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916>\
**Category:** Android\
**Created:** [November 15, 2020, 4:02pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916 "2020-11-15T16:02:10Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 15, 2020, 4:02pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/1 "2020-11-15T16:02:10Z")

</div>

Hello. I’m not sure if I can pass my data from an overriden function and can use `Flow` to pass the data from `Repository` to `ViewModel`. Here in example with `Firebase` I have a _Suspension functions can be called only within coroutine body_ error. Maybe I could rewrite it somehow?

**Repository**

```auto
    fun fetchFirebaseFlow(): Flow<List<MyData>?> = flow {
        var ret: List<MyData>? = null
        firebaseDb.child("data").addListenerForSingleValueEvent(
            object : ValueEventListener {
                override fun onDataChange(dataSnapshot: DataSnapshot) {
                    val data = dataSnapshot.getValue<List<MyData>>()
                    emit(data) // Error. How to return the data here?
                }

                override fun onCancelled(databaseError: DatabaseError) {
                    emit(databaseError) // Error. How to return the data?
                }
            })
// emit(ret) // Useless here
    }

```

**ViewModel**

```auto
    private suspend fun fetchFirebase() {
        repo.fetchFirebaseFlow().collect { data ->
            if (!data.isNullOrEmpty()) {
                // Add data to something
            } else {
                // Something else
            }
    }

```

---

<div class="post-metadata">

**Author:** ![nickallendev](https://avatars.discourse-cdn.com/v4/letter/n/cdc98d/32.png) [@nickallendev](https://discuss.kotlinlang.org/u/nickallendev)\
**Post date:** [November 15, 2020, 10:31pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/2 "2020-11-15T22:31:13Z")

</div>

Seems like you are looking for [callbackFlow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/callback-flow.html).

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 16, 2020, 8:00am UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/3 "2020-11-16T08:00:02Z")

</div>

Yes, I tried it as it was recommended but my `fetchFirebaseFlow` became suspended and proceed only once in a loop. Also I tried `MutableStateFlow` but it returns data twice (first one with initialization) and also my function became suspended.

---

<div class="post-metadata">

**Author:** ![nickallendev](https://avatars.discourse-cdn.com/v4/letter/n/cdc98d/32.png) [@nickallendev](https://discuss.kotlinlang.org/u/nickallendev)\
**Post date:** [November 16, 2020, 1:13pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/4 "2020-11-16T13:13:20Z")

</div>

It’s not really clear what you’re issue is. Coroutines suspend, that’s kind of the point.

Is the issue that you have code after `fetchFirebase` that is not running? If so then you can `launch` a coroutine and call `fetchFirebase` inside. The new coroutine will suspend but not the code that launched it.

---

<div class="post-metadata">

**Author:** ![miho39](https://avatars.discourse-cdn.com/v4/letter/m/65b543/32.png) [@miho39](https://discuss.kotlinlang.org/u/miho39)\
**Post date:** [November 18, 2020, 9:01am UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/5 "2020-11-18T09:01:30Z")

</div>

Sure ! callBackFlow can solve this case

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 22, 2020, 5:08pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/6 "2020-11-22T17:08:12Z")

</div>

This loop repeats only once:

```
init {
        viewModelScope.launch(Dispatchers.IO) {
        for (i in 0..2) {
            fetch().collect {
                if (it.isNullOrEmpty()) {
                    //
                } else { }
            }

        }
    }
}

val firebaseDb: DatabaseReference = Firebase.database.reference

@ExperimentalCoroutinesApi
private fun fetch(): Flow<List<Data>?> = callbackFlow {
        val listener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                val data = dataSnapshot.getValue<List<Data>>()
                offer(data)
            }

            override fun onCancelled(databaseError: DatabaseError) {
            }
        }
        val ref = firebaseDb.child("data")
        ref.addListenerForSingleValueEvent(listener)

        awaitClose{
            //remove listener here
            ref.removeEventListener(listener)
        }

}

```

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 22, 2020, 6:09pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/7 "2020-11-22T18:09:35Z")

</div>

I asked this question in [another topic](https://discuss.kotlinlang.org/t/function-stops-after-collect-in-callbackflow/19991) because it’s not only about Android.

---

<div class="post-metadata">

**Author:** ![nickallendev](https://avatars.discourse-cdn.com/v4/letter/n/cdc98d/32.png) [@nickallendev](https://discuss.kotlinlang.org/u/nickallendev)\
**Post date:** [November 22, 2020, 6:19pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/8 "2020-11-22T18:19:38Z")

</div>

`Flow.collect` is like `Sequence.forEach`, it starts the “lazy” collection and doesn’t stop until the collection says it is done.

So a `Flow` that never finishes like the one you’ve implemented, will cause `collect` to never return.

`awaitClose` doesn’t return until the `Flow` is canceled by the collector or closed by the `Flow` implementation (otherwise it would finish immediately without any data). Neither happens in your code above.

You could fix your code by calling `close` after `offer`.

Honestly, `Flow` is not the best tool for returning a single async value. That’s like passing around a `List<Int>` when all you have is an `Int`. Plain old suspend methods are best for single results.  
`callbackFlow` is perfect for wrapping `addValueEventListener`, but for wrapping `addListenerForSingleValueEvent`, I’d suggest using [suspendCancellableCoroutine](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/suspend-cancellable-coroutine.html). Then `fetch` would become just a suspend method.

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 22, 2020, 6:27pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/9 "2020-11-22T18:27:05Z")

</div>

Thanks.

P.S. actually, I use the loop to fetch different data from Firebase, so, could be it a good idea to use flow in this case if I move the loop within `fetch()`?

---

<div class="post-metadata">

**Author:** ![nickallendev](https://avatars.discourse-cdn.com/v4/letter/n/cdc98d/32.png) [@nickallendev](https://discuss.kotlinlang.org/u/nickallendev)\
**Post date:** [November 22, 2020, 10:33pm UTC](https://discuss.kotlinlang.org/t/emit-flow-data-from-an-event-listener-function/19916/10 "2020-11-22T22:33:45Z")

</div>

You are probably best served by writing a general helper (something like `suspend FirebaseReference.fetch(): DataSnapshot`) and the using that however you need.

> [@Psijic](#):
>
> could be it a good idea to use flow in this case if I move the loop within `fetch()` ?

`Flow` works best if you are getting data over time and acting on that data as it comes in (as opposed to accumulating it into a data class or collection before processing) . I can’t really tell if that’s your scenario or not.
