Reputation: 492
I'm confused about using MVVM architecture! In some tutorials, LiveData
is stored in a repository and then passed to the ViewModel
. In many others, LiveData
is defined within a function of repository and passed to the ViewModel
using the result of the function. But Google says:
It may be tempting to work LiveData objects in your data layer class, but LiveDatais not designed to handle asynchronous streams of data. ........ If you need to use streams of data in other layers of your app, consider using Kotlin Flows and then converting them to LiveData in the ViewModel using asLiveData(). .... For codebases built with Java, consider using Executors in conjuction with callbacks or RxJava.
I prefer to use Kotlin coroutines
or Flows
. But I do not know if in my case is really needed or not. I'm working on a chat application. When a message is received, a listener is called in the repository and the message data is received in it. (The listener runs in the background thread) Now I want to send the message object to the ViewModel
and add it to a LiveData
that stores the list of messages.
object ChatsRepo {
fun listen(socket: Socket) {
socket.on(Config.ON_MESSAGE, onMessage)
}
fun sendMessage(socket: Socket, json: String) {
socket.emit(Config.ON_MESSAGE, json)
}
private val onMessage = Emitter.Listener { args: Array<Any> ->
//This message object must be sent to ViewModel
val message = Gson().fromJson(args[0].toString(), Message::class.java)
}
}
I can easily do this using the higher-order function:
object ChatsRepo {
lateinit var listener: (Message) -> Unit
private val onMessage = Emitter.Listener { args: Array<Any> ->
val message = Gson().fromJson(args[0].toString(), Message::class.java)
listener(message)
}
}
But is it better to use Kotlin coroutines
or Flows
? In some similar cases, a list needs to be sent to the ViewModel
.
Upvotes: 1
Views: 3419
Reputation: 1030
Livedata was never design for reactive streams it was always been for last layer (viewmodel to view)
, there were/are workaround when livedata was use with retrofit(using calladapter) and room(which google did it).
And now since the rise of coroutines recommended ways is to use kotlin Flows
when dealing with business logic but things to be notice:
1- regular flow
are not observables but livedata is observable.
2- it's not good to manage UI state with regular flows
but you can do it with livedata
.
3- livedata is lifecycle aware
but flows are not.
4- livedata
is not reactive but flows
are.
5- livedata
gives you the only latest value what it receives but regular flows
throws values from bucket one by one
you might have notice i said alot of regular flows
not flow
cause there are other mechanism related to flows you can manage UI state that are stateFlow
and sharedFlow
.
Stateflow is the replacement of livedata
the downside is you have to code a little bit more to make it lifecycle aware cause it is not prebuilt and stateflow always gives you the last value it persists during the configuration changes or screen switching(fragment navigation).
sharedFlows
is good for managing the one time event like toastMsgs, snackbar etc. sharedFlow
was actually the replacement of BroadcastChannels
.
Upvotes: 1
Reputation: 30725
I can easily do this using the higher-order function.
Right, this is a callback you can use to notify ViewModel
about new messages. Kotlin Coroutines help to avoid callbacks and to have a sequential code.
In your case the onMessage
is a hot stream of data, we can convert it to a hot Flow
using SharedFlow
:
private val _messagesFlow = MutableSharedFlow<Message>(extraBufferCapacity = 64)
val messagesFlow: SharedFlow<Message> = _messagesFlow
private val onMessage = Emitter.Listener { args: Array<Any> ->
val message = Gson().fromJson(args[0].toString(), Message::class.java)
messagesFlow.tryEmit(message)
}
In ViewModel
if need it is easy to convert it to LiveData
using method asLiveData
:
ChatsRepo.messagesFlow.asLiveData()
Dependency to use asLiveData()
extension function:
def lifecycle_version = "2.4.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
Upvotes: 4
Reputation: 286
If you are a Rxjava master, I will not recommend you to use flow/livedata. I think flow/livedata is designed for UI Reactive, not for underlying data transform. So you can use rxjava in data repository, and in viewmodel, you can convert it to livedata and use it.
Upvotes: 1