https://kotlinlang.org logo
#decompose
Title
# decompose
d

Djuro

03/01/2024, 10:42 AM
Hello, hope you are all doing well 👋 I have a question. Is there a subtype of
MutableValue
or similar that doesn't reemit the same value. I am interested if there is something provided by the lib that has this behaviour. I noticed that `MutableValue`'s
compareAndSet
reemit the same values. Is there if not that, then at least an atomic
get
that uses a mutex/lock so that I could perform a check before I
update
my
MutableValue
?
a

Arkadii Ivanov

03/01/2024, 11:29 AM
You want to not emit the new value if it's equal to the previous one?
d

Djuro

03/01/2024, 12:07 PM
yes, similar to
Flow.distinctUntilChanged()
a

Arkadii Ivanov

03/01/2024, 12:21 PM
Yeah, the documentation for
MutableValue#compareAndSet
specifically mentions "the comparison is preformed by reference". Though, I'm open to consider using
equals
instead, similarly to
MutableStateFlow
. The original idea was to replicate Rx
BehaviorSubject
. WDYT? Currently there is no out-of-the-box way of achieving the desired behaviour. Though, since it's a state holder (not suitable for events in general), it shouldn't really matter and the UI should handle it just fine.
d

Djuro

03/01/2024, 12:36 PM
I think this implementation is a classical observer pattern approach and that's totally fine though people coming from the Android world would maybe expect it to act as a state flow when using it as a state holder. It would be nice if we had at least an option to have that comparison performed by value. Might be useful for migrations from
StateFlow
also. As you mentioned, since it is a state holder in most cases, no need to emit the same value twice
a

Arkadii Ivanov

03/01/2024, 1:01 PM
What issues do you have currently?
d

Djuro

03/01/2024, 1:27 PM
I am using
Value
as a state holder. State is gradually being updated. It depends on a couple of api requests. I use
subscribe
to observe these states and when specific new state is observed, then I update it to the new one. There is even one case where I need to wait for an api response before I update the state. Now for the last state (let's call it
Complete
) It has for example a
List<String>
representing the data. State can go from
Complete
to
Complete
again. Whenever
Complete
is collected it will trigger a check to see if this list has changed. If it has changed, update the state, otherwise don't do it. When using for example
Copy code
value.update{
    if(conditionSatisfied) newState
    else it
}
It will reemit itself there and
Component
subscribed to this value change will end up in an infinite loop causing an ANR. I can use value on its own and do a check but this check should be done atomically to avoid race conditions IMO. At the moment I do the check using the value I got when subscribed
Copy code
newObservedValue.getFilteredValue().takeIf { it != newObservedValue )?.let{
   value.compareAndSet(newObservedValue, it)
}
This works now, the only thing I am scared of is race condition leading to an invalid state in the end
a

Arkadii Ivanov

03/01/2024, 1:36 PM
Thanks! > It will reemit itself there and
Component
subscribed to this value change will end up in an infinite loop causing an ANR. This sounds scary, and I believe you might be doing something wrong. I wouldn't recommend relying on the equality behaviour here. Usually in such cases I recommend using StateFlow or Rx, and do something like
map { it.useful_part_of_the_state }.distinctUntilChanged()
. So that the semantics is explicitly defined in the code.
d

Djuro

03/01/2024, 1:39 PM
Okay, I will drop
Value
API in this case then, or maybe just convert it using the snippet you provided
a

Arkadii Ivanov

03/01/2024, 1:47 PM
Yep, this is what I would recommend. You can use Flows (or whatever reactive lib you like) and then convert to Value. Please note that Value is mostly useful if you need to expose it outside of Kotlin (e.g. in Swift).
thank you color 1
🆒 1