Do coroutines flows replace LiveData, or should th...
# android
d
Do coroutines flows replace LiveData, or should they be used side by side? If they do replace them, is it enough to use the view's lifecycle scope to manage cancelling when the view is gone?
a
it depends 🙂 in most cases they should be used side by side
g
I agree with Andriy in terms of that It depends on what you use from coroutines. If just suspend functions, than yes, side by side. But I would argue, that it’s not most of cases, if you already use Flow and/or Channels, I don’t see reasons to use LiveData for most cases (maybe only for integration with existing Androix APIs using adapter)
đź‘Ť 1
(the same for Rx)
r
It's common to see CoroutineScope implementations (including in the v2.1 and v2.2 versions of lifecycle) where the scope is just cancelled in a terminal function like
onStop()
. If you're using a coroutine to observe a
Channel
, then the observer will continue to operate during
onPause()
whereas a
LiveData
observer would not. Imagine that your
MainActivity
started an observer like this, then it ran in the background for the full lifetime of the app (so long as
MainActivity
is in the backstack). I did a talk just last week on how I handle observing with Channels and coroutines. I talk about one solution to the `CoroutineScope`/lifecycle relationship. You can check it out here:

https://youtu.be/WIL6xw8cRwAâ–ľ

d
Nice, thanks, I'll take a look!
p
Looking at LiveData internal implementation I see there is risk in losing some events, there are a couple of comments internally in the class that support my statement. It behaves similar to a switch operator in Rxjava. I wouldn't take this risk.
g
risk in losing some events
Which is also true for BehaviorSubject if you use it concurrently
p
Yes, although the behavior subject can be fix with one line of code to make it sequentially dispatch on one single thread. I don't see a possibility to fix livedata
r
No, they have different usecase. They are not in direct competition with each other
g
It’s not correct
r
What do you mean?
g
ConflatedBroadcastChannel and upcoming DataFlow has exactly the same use case as LiveData: observable data holder
r
You mean they are capable of accomplish the same task. They are not the same usecase
LiveData is not
One conflatedBroadcastChannel and DataFlow, are ways of communicating via coroutines
g
are ways of communicating via coroutines
Not necessary, but anyway, question was “should they be used side by side”, and if you already have coroutines I see no reason to use LiveData at all, it’s very simple (which is good), but very limited (which is bad) thing and if you use RxJava/Flow/Channels together with LiveData instead of just exposing one of those streams of events you have to redeliver events from one abstraction to another with no real reason
đź’Ż 2
đź‘Ť 2
r
@gildor that is there exact use case, to communicate between coroutines... if you need to send messages from one coroutine to another use channels. If you need to send message from one coroutine to multiple coroutines use broadcastchannels. LiveData is just a data holder than works with lifecycle awareness. It doesnt deal with concurrency at all. So depending on your usecase you may not even need to start up a coroutine, and at that point livedata would make more sense
g
LiveData is just a data holder than works with lifecycle awareness
The same as coroutines with structuredd concurrency
r
Lol no
They are different fundamentally. They work completely different
g
scope is lifecycle aware component
I agree, implementation is different, but both are safe, just used in a different way
r
They maybe able to accomplish the same task, theoretically. But to say they are the same is a very long stretch
g
I do not say that they are the same, I’m just saying that if you use proper asyncronous library like RxJava or kotlinx.coroutines I don’t see good use cases for LiveData
very-very limited use case of LiveData becoming disadvantage in this situation
r
RxJava is different lol. Coroutines is different... Live Data is different. For instance LiveData is a very simple object and very easy to understand implementation. So for observing simple things from inside a viewmodel, you would/should use livedata ... Like there are certain things that you wouldn't have to wrap in a observable or start up a coroutine for .
g
instance LiveData is a very simple object and very easy to understand implementation
I agree with it. I don’t say that if you have only LiveData you should migrate to coroutines or rx, I just say that if you already use coroutines or rxjava, you probably also understand them.
r
If your needing to manipulate stream of events , and jumping between threads while doing so, Rx Java still rains supreme
g
if you need observable data holder RxJava also supreme
r
I would disagree with that
Rxjava also comes with alot of code . Livedata doesnt. That code is to help you manipulate a continuous stream of events. But if your not manipulating anything, than it's just extra bloat
g
Rxjava also comes with alot of code
again, returning to original question. If you already have rxjava, this is not a problem, you already have this library
r
Lol but for observing a simple object change why would you wrap that in a observable ?
g
What is problem? BehaviorSubject has almost exactly the same amount of code as LiveData implementation Also provides more features because of good integration with other parts of Rx
r
Lol but you may not need those other features . Livedata is just a data holder. Rx is not just a data holder. Corutines is not just a data holder. If you need just a data holder, best practice is to use liveData
Lol
If you want a more complicated practice use the other two lol
They are great libraries but fundamentally different
g
they are not fundamentally different, both of them provide own implementation of observable data holder which the same use case as LiveData And again, I do not advocating to use Rx or coroutines just to replace LiveData, it would be really overkill by itself, my point that if you already user of Flow/Channels/Observables/Flowable, adding LiveData wouldn’t give you any advantages
r
Your not going to need to wrap everything in a coroutine. Just like your not going to need to wrap everything in a single or observable .Like for instance , let's say I just want to observe a boolean value on the main thread from my viewmodel to my fragment.... just a simple boolean value. And let's say you have all 3 opotions.are you saying your willing to wrap that boolean value in a coroutine or observable just to observe it?
g
what do you propose? wrap to LiveData? %)
depends on use case, you also can use Kotlin Delegates.observable() for example, but in general LiveData for described use case is not better at all
p
I think LiveData is purposeless, sorry if I hurt the engineers at Google who designed it. The only reason people has that thing in their code is because Google remind us it exist in every single Android conference. Implementation only covers .map and . switchMap transformation, the easy ones to implement since they don't mess up with threading. 🙂
g
Tho I thinking that it doesn't make sense to use it if you use Rx or coroutines, but I don't think that it purposeless, it's missing component on Android, you need some observable data holder for UI, it's just missing component for Android, you need it for room, for data bindings, for viewmodel and it's better than raw callbacks
p
Well, for a company that don't like to include third party libraries that's right. Also is better than raw callbacks too. As you said it is basically a data holder for UI. Or better said a Shared Data holder. For data holding I prefer coroutines, more specifically actors and channels.
g
I agree for sure, but you cannot use coroutines in Java and RxJava is overkill for their use case, it'simple and lightweight to include to any project where you need such abstraction
And they also support RxJava and coroutines, so in general sounds like a reasonable decision for me
p
Definitely there is market for them but I think it will shrink as more people move to Kotlin and Coroutines. I don't use them though.
r
@Pablichjenkov even if you have coroutines in your codebase, there is still a usecase for LiveData. Not everything you observe needs to be behind a suspended function. They can co exists fairly easy
actors are for transmitting data in between coroutines .. so you wouldn't just use them as a dataholder. and if you did that would somewhat weird lol
p
My concern with LiveData is not really its frustrated goal of trying to replace RxJava. That purpose is fine and I really support that Google should have its own implementation of a reactive stream library. Apparently https://github.com/google/agera was not successful and I don’t think it is complaint with the reactive manifest too. https://www.reactivemanifesto.org/ Now, I kind of agree that having an event dispatcher class built in the framework is nice. However, I still see some assumptions in the implementation that makes me think twice before using LiveData.
See the two screenshots above. 1: It behaves as the
switch
operator in RxJava by default. It may not be terrible for receiving events in a UI observer, since you don’t want to make un-necessary screen updates and showing the latest is fine. However, if your observer is not of UI type and is a business logic type of observer, then losing events is not joke. This fact limits LiveData to only be suitable for UI kind of observers.
2: This one is more dramatic and I definitely don’t like it. The event is dispatched in a traditional loop, without isolating the observers in different channels. As a consequence if the first observer performs an action that invoke a
mData
change in the same Thread where the event is dispatched, then everything become a mess. Apparently they guard against this by using
mDispatchingValue
and
mDispatchInvalidated
but again will cause the previous event being lost for some observers. No problem for UI observers but big issue for business logic observers.
I share this file where you can see the latest trends in observance pattern. The classic loop dispatching on a single thread is obsolete although still used in many places as the author said.
Now, regarding Actors. Actors has been probably the most successful pattern for state or data holding. You mentioned one use of it, which is sharing data through its channel. However, Actors are coroutines too. The whole point behind coroutines, or better said structured coroutines, is encapsulate a set of asynchronous operations over a single scope. Nothing stops you to put any data you want to in that scope. With actors you get the benefit that all external request to modify your scope will be processed sequentially in a pipe. There is no danger of accessing from different threads.
In regards of “how to replace LiveData with an Actor”. Nothing stops you to have an Actor coroutine in your View. Then you give a reference of this actor to your ViewModels or DataManagers. They will deliver events to the actor. When your View stops you simply inform the ViewModel or DataManager to remove the actor reference so no memory leaks are left over. Advantages: No more event losing, events are put in the actor queue as they arrive and dispatched accordingly. My point of view is: If you plan to go reactive, then go fully reactive with a complete solution(AKKA, RXjava,Spring-Reactor,Kotlin-Flow, Apple-Combine) otherwise don’t go reactive at all.
r
@Pablichjenkov there is a misconception here. LiveData isn't here to replace RXJava nor is it a reactive streams library. It wouldn't even scale as a reactive streams lib.. The creators themselves have made this statement multiple times. Even at the last Google IO they said that lol. The postValue method isn't like RXjava switch method. Its a post method, Even the View class has a post method. LiveData , is just a observable dataholder that can be lifecycle aware. Thats all it is,nothing more nothing less. If you want a piece of data observed by something that has a lifecycle , than using livedata is a valuable solution. If you want reactive streams, RX java is a great solution. if you want to handle concurrency in your app corourtines is a way better solution than Threads. Everything has its own domain, and you can even use all 3 of these things together,
Not everything you want to observe in your app, your going to want to do behind a actor . and if you did that would be overkill. Like Doomsday killing Superman overkill.... Using things where things make logic sense and following the best practices is important... One reason is because when people see your codebase, they understand exactly what your trying to accomplish from the start. Instead having to process why certain things where done, only to realize it was for no reason, besides an architectural one
p
I agree in regards to “Using things where things belong” and I also think that the best architecture is the one that better solve your particular problem.