Once in a while, I am getting the affect one wishes 42 hours of study and a PhD dissertation to determine the way to ship a one-time match from the ViewModel layer to the UI safely nowadays.
Memes apart, it appears like there’s no “true” consensus on the way to do one of these easy factor in 2 strains. Each and every way has gotchas, questionable antipatterns, numerous boilerplate, or it seems that does no longer paintings in edge circumstances.
Why no longer upload to the confusion with any other take, then?
Houston, we now have an issue
Lengthy tale quick, one-time occasions will have to be a part of the all-encompassing UI state throughout the ViewModel, treated accordingly within the UI layer. Setting apart occasions to their very own move is naughty.
I don’t essentially disagree with them, to be fair. However I do suppose this can be a bit overboard for 99.8% of circumstances in the market.
It additionally introduces guide steps to take care of/reset the state on the proper time, thus leading to a possible failure level that might no longer exist another way.
Once in a while, you simply want a little bit of a caveman way that simply works and is unit-testable. Must it in reality be this difficult? 😰
They don’t seem to be supposed for use for one-time occasions out of the field, as they’re observable state holders.
A just right instance is sending an match to navigate to any other display, whilst the present display remains within the again stack.
Urgent again, the remaining match shall be learn once more, leading to a clumsy loop of going ahead to the opposite display once more!
This can be have shyed away from with extra paintings, as described via the Google information. If this is fascinating to you, extra main points may also be discovered right here.
SharedFlow — He’s useless, Jim
SharedFlow appears to be the easiest candidate for a move of one-time occasions. Which means:
- An match is emitted to the float.
- The collector within the compose layer receives it and does one thing with it.
- As soon as ate up, the development received’t be noticed once more, for instance when rotating the display.
Sounds very best? No longer in reality.
Go with the flow assortment within the UI layer will have to be carried out simplest whilst the lifecycle is above the
STARTED state, to save some assets. (see extra right here)
Believe an match emitted to the
SharedFlow to navigate to any other display, whilst the UI is within the
PAUSED state. The outcome?
- The collector might not be there to obtain it.
- The development is misplaced ceaselessly.
- The person used to be by no means redirected to the following display. We’ve an irrelevant state and a 1-star evaluation.
Choice 2— StateFlow + SingleLiveEvent — It’s alright, I suppose?
One-time occasions were a sizzling matter because the days of
LiveData. This elegance most certainly exists in 95% of apps in the market.
LiveData is deprecated™, so let’s take a look at the usage of it with
This to begin with works, despite the fact that it appears to be like a little bit meh.
One would be expecting to look the similar match again and again, on rotation for instance, because of the character of
StateFlow, however the
getContentIfNotHandled serve as guards by contrast.
There’s one factor with it regardless that.
StateFlow at all times assessments for equality between the remaining and the brand new price when it will get up to date. If each are the similar, the brand new price might not be emitted to the collector.
knowledge elegance SingleLiveEvent can not be used as is, which is a disgrace as knowledge categories are very handy when unit trying out.
It needs to be transformed to a standard
Why is that?
Believe a state of affairs the place you wish to have to ship the similar match two times in a row. This isn’t so unusual! A large number of the days, a person would take a look at one thing time and again, leading to precisely the similar error. (a toast, for instance)
- Replace the float for the primary time. This will have to paintings positive.
- Replace the float for a 2nd time, with precisely the similar match.
StateFlowcompares previous and new values internally.
- Sees them as precisely the similar. (it’s a knowledge elegance, it does no longer take a look at for reference equality, however what’s within them)
- As they’re the similar, emission shall be skipped.
- 2nd match is misplaced.
There’s a workaround round to this. A singular timestamp/ID may also be added to each and every match.
No longer superb, however hello, it really works.
Choice 3— Channel + Go with the flow
As discussed within the
TL;DR, however no longer together with
Dispatchers.Primary.fast this time:
What are the benefits of this way?
- It really works despite the fact that the collector isn’t there when the development is emitted. The development shall be stored within the float, till the collector comes again to the
STARTEDstate to devour it.
- Minimum boilerplate.
- Simple to unit check and reason why about.
- No additional common sense wanted.
But in addition some disadvantages:
- Does no longer paintings with a couple of concurrent creditors.
- There is the tiny risk of lacking an match.
The latter is because of the slight variations of
Dispatchers.Primary.fast. Astute observers may also understand that
viewModelScope is in reality the usage of
Emitting loads of occasions in a very quick period of time whilst repeatedly rotating the app can reflect this factor.
Should you in reality wish to take care of even the largest of edge circumstances, then the float needs to be accumulated on
In any case
This listing isn’t exhaustive whatsoever. There are possibly 15 others techniques to do this kind of stuff, which are most certainly out of scope of a brief little weblog put up.
Hope you discovered this reasonably helpful.