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.
CodePudding user response:
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"
CodePudding user response:
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.
