https://kotlinlang.org logo
Title
k

kevin.cianfarini

09/05/2019, 7:24 PM
If I'm using
Flow
as the bridge between a VM and a fragment, how can I ensure that the callback I use for the flow is initialized before I need It? The way I'm approaching it now seems like an antipattern.
private var loadedPosts: List<Post> = emptyList()
    private lateinit var loadedPostsCallback: LoadedPostsCallback
    val posts: Flow<List<Post>> = callbackFlow {
        val callback = object : LoadedPostsCallback {
            override fun setLoadedPosts(posts: List<Post>) {
                loadedPosts = loadedPosts + posts
                offer(loadedPosts)
            }
        }
        loadedPostsCallback = callback

        awaitClose()
    }
when setting everything up in the fragment, I start a new coroutine to observe the
posts
. However, the
loadedPostsCallback
isn't initialized when I try to do the initial load from
loadPosts()
.
The idea I have right now is to
suspendCoroutine
until I can ensure everything is initialized correctly, but I feel like there's a better way
nevermind. Avoiding
callbackFlow
and using a backing channel of my own made this easier
d

Dominaezzz

09/05/2019, 7:37 PM
Why can't you init
loadedPostsCallback
inside
callbackFlow
?
Yeah, was about to hint at that.
k

kevin.cianfarini

09/05/2019, 7:38 PM
@Dominaezzz I did, but the flow wasn't actually being initialized because that block didn't get run until
collect
was being called
using my own backing channel makes it much easier to read too 😅
d

Dominaezzz

09/05/2019, 7:51 PM
You could call
produceIn
and turn the flow into a channel.
k

kevin.cianfarini

09/05/2019, 7:51 PM
I ended up with this
private val postsChannel: Channel<List<Post>> = Channel(CONFLATED)
    val posts: Flow<List<Post>> = flow {
        postsChannel.consumeEach {
            loadedPosts = it
            emit(it)
        }
    }
and just use
Channel.offer
as the callback
d

Dominaezzz

09/05/2019, 7:55 PM
Hmm, I feel like this could definitely be improved somehow.
k

kevin.cianfarini

09/05/2019, 7:56 PM
yeah it definitely doesn't feel as easy as LiveData. There's got to be something I'm missing
d

Dominaezzz

09/05/2019, 7:59 PM
You should be able to do this with,
callbackFlow {}.onEach {}.launchIn(coroutineScope)
.
k

kevin.cianfarini

09/05/2019, 8:00 PM
not quite sure how to apply that to something like the snippit above
d

Dominaezzz

09/05/2019, 8:02 PM
Can
loadedPostsCallback
be initialised and registered inside a flow? (Do you need a context or smth)
k

kevin.cianfarini

09/05/2019, 8:07 PM
no, but I did need to make the callback from within the flow or else I wouldn't be able to offer in the flow scope
right?
d

Dominaezzz

09/05/2019, 8:09 PM
Ah, I misread. Channel seems to be what you need.
k

kevin.cianfarini

09/05/2019, 8:09 PM
cool 🙂