I there a way to use Android Live-Data in Jetpack ...
# compose-desktop
f
I there a way to use Android Live-Data in Jetpack Compose Destkop?
b
The only benefit of LiveData over other reactive libraries (Kotlin Flows, RxJava) is that it is aware of the Android Lifecycle. For desktop, you probably don’t care about the Android Lifecycle and would be better off with a different library 😉
😆 1
f
ok
I mean I have a channel which I’m sending data to
but this channel is not taken into consideration to update the UI
it is only done once
and then never again
I was looking for something like this observeAsState - function
but I this functionality is only in livedata
b
f
I’ve tried this :
Copy code
vm.countChannel.consumeAsFlow().collectAsState(99)
But this works only once
Initially it displays 99
and then 1
but then it doesn’t change anymore
a
does
countChannel
need to be a channel or could it be snapshot state? e.g.
Copy code
var count by mutableStateOf(99)
  private set
accessing
vm.count
directly in your
@Composable fun
will observe updates to
count
made from elsewhere.
f
This doesn’t work
the value in the UI doesn’t change
Basically I want to observe a property in my viewmodel
modify it when a button is clicked and this change should reflect in the UI
It works with the channel the first time
maybe there is something wrong in my mode
a
if snapshot state didn't update a compose UI when it changes then all of compose wouldn't work at all 🙂
f
In my constellation it doesn’t work. I have to check my code
How does this code observe my counter?
Ok I will check this
d
Don't forget to
remember
the right stuff.
1
f
Thanks - I will try that tomorrow. And after that I want the channel to work somehow.
m
@Frank Don’t hit the Return key after every line of text here. Use Shift-Return, like I just did, to go to a new line 😉 Otherwise you will post each line as a separate message.
f
ok
I’ve tried the Channel-Solution again. When I send the first value to the channel the UI get’s updated with this value. Successive values lead to an exception: kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelled}@47c42b90 I have no idea why this happens.
When I’m send a value to the channel using trySend. If I used send(value) the second call blocks forever. I observe the channel in the composable using this line of code:
Copy code
val cc: State<Int>  =   vm.countChannel.consumeAsFlow().collectAsState(0)
d
Try
val cc: State<Int>  = remember(vm.countChannel) { vm.countChannel.consumeAsFlow() }.collectAsState(0)
f
Holy sh… - it works! Thank you! I only need to understand your magic code now 😉 ,
Is there some kind of API-Documentation which explains all the different versions of “remember” - I didn’t know about this signature. I’ve never seen it before. I’ve only encountered the “simple” version like this:
Copy code
val s = remember { mutableStateOf(0) }
So what I understood is: The “key” in the remember-function saves the value of the current calculation function. In the next compose - cycle it checks if the value under this key is equal to the previous cycle. If so it takes the cached value - if not it executes the calculation function again,
d
That's about right
a
now that you've got the mechanics up and running there are some conceptual issues to deal with in this setup that will continue to bite you down the line, so it's probably best to take a look at them sooner rather than later. 🙂 Using a Channel to funnel state from a viewmodel to a collectAsState in a composable means that observing your viewmodel is not idempotent and has side effects. Your composable isn't just observing the channel, it's consuming from it.
👍 1
Part of this is at the root of the trouble you were having before - by using
Channel.consumeAsFlow
you were not only consuming values from the viewmodel - changing the viewmodel as you receive those values from the channel -
consumeAsFlow
enforces a single collector and cancels the channel after that single collector cancels the collection of the converted flow. Recomposing without the
remember
meant
collectAsState
cancelled collection of the flow to start collection of a new one, but that cancellation also rendered the channel unusable for the future.
🙌 1
1
👍 1
and the trouble doesn't stop there; if you have two composables on the screen observing the same viewmodel, they can't both see updates to the count, since the channel is delivering values to only one of them.
If you changed
Channel.consumeAsFlow
to
Channel.receiveAsFlow
then it won't enforce only a single collector or cancel the channel, but it will fan-out values instead, so if you have multiple composables observing that same viewmodel again, some values would go to composable A and some would go to composable B
👍 1
it's almost certain that you want to use
mutableStateOf
to store the count here instead. If you wanted to be more complicated about it you could use a
StateFlow
.
Observers don't consume the value of observable state holders like these, making them safe for use as a source of truth in a viewmodel.
f
@Adam Powell The purpose of using a channel is to get experience in developing more complex solutions. I know that using a channel for a simple counter is a overkill. But these are the first prototyping steps to develop a MVVM-Architecture for a more complex application. But thank you for the tip with the fan-out - I will very likely need that.
@Adam Powell And how can I emit a value to a StateFlow?
d
There's an emit method lol. The proper way is to set
.value
.
😉 1
👀 1
f
@Adam Powell Ok - I got the StateFlow ( MutableStateFlow ) working.
@Dominaezzz Thanks! I got so confused with all this stuff I didn’t see it.