[英]Send data from repository to view model in MVVM architecture
I'm confused about using MVVM architecture, In some tutorials, LiveData
is stored in a repository and then passed to the ViewModel
.我对使用 MVVM 架构感到困惑,在一些教程中,
LiveData
存储在存储库中,然后传递给ViewModel
。 In many others, LiveData
is defined within a function of repository and passed to the ViewModel
using the result of the function.在许多其他情况下,
LiveData
中定义,并使用 function 的结果传递给ViewModel
。 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.
在数据层 class 中使用 LiveData 对象可能很诱人,但 LiveData 并非旨在处理异步数据流。 ........ 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().
........ 如果您需要在应用程序的其他层中使用数据流,请考虑使用 Kotlin 流,然后使用 asLiveData() 在 ViewModel 中将它们转换为 LiveData。 .... For codebases built with Java, consider using Executors in conjuction with callbacks or RxJava.
.... 对于使用 Java 构建的代码库,请考虑将 Executors 与回调或 RxJava 结合使用。
I prefer to use Kotlin coroutines
or Flows
.我更喜欢使用 Kotlin
coroutines
或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 发送到
ViewModel
并将其添加到存储消息列表的LiveData
中。
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:我可以使用高阶 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
?但是使用 Kotlin
coroutines
还是Flows
更好? In some similar cases, a list needs to be sent to the ViewModel
.在一些类似的情况下,需要向
ViewModel
发送一个列表。
I can easily do this using the higher-order function.
我可以使用高阶 function 轻松做到这一点。
Right, this is a callback you can use to notify ViewModel
about new messages.是的,这是一个回调,您可以使用它来通知
ViewModel
新消息。 Kotlin Coroutines help to avoid callbacks and to have a sequential code. Kotlin 协程有助于避免回调并具有顺序代码。
In your case the onMessage
is a hot stream of data, we can convert it to a hot Flow
using SharedFlow
:在您的情况下,
onMessage
是数据的热Flow
,我们可以使用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
:在
ViewModel
中,如果需要,很容易使用asLiveData
LiveData
ChatsRepo.messagesFlow.asLiveData()
Dependency to use asLiveData()
extension function:使用
asLiveData()
扩展 function 的依赖项:
def lifecycle_version = "2.4.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
If you are a Rxjava master, I will not recommend you to use flow/livedata.如果你是 Rxjava 高手,我不会推荐你使用 flow/livedata。 I think flow/livedata is designed for UI Reactive, not for underlying data transform.
我认为 flow/livedata 是为 UI Reactive 而设计的,而不是为底层数据转换而设计的。 So you can use rxjava in data repository, and in viewmodel, you can convert it to livedata and use it.
所以你可以在数据仓库中使用 rxjava,在 viewmodel 中,你可以将它转换为 livedata 并使用它。
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). Livedata 从来都不是为反应流设计的,它总是用于
last layer (viewmodel to view)
,当 livedata 与改造(使用 calladapter)和房间(谷歌做到了)一起使用时,有/有解决方法。
And now since the rise of coroutines recommended ways is to use kotlin Flows
when dealing with business logic but things to be notice:而现在由于协程的兴起推荐的方式是使用
kotlin Flows
来处理业务逻辑但是需要注意的事情:
1- regular flow
are not observables but livedata is observable. 1-
regular flow
不是可观察的,但 livedata 是可观察的。
2- it's not good to manage UI state with regular flows
but you can do it with livedata
. 2-使用
regular flows
管理 UI state 并不好,但您可以使用livedata
来做到这一点。
3- livedata is lifecycle aware
but flows are not. 3- livedata 是
lifecycle aware
的,但流不是。
4- livedata
is not reactive but flows
are. 4-
livedata
不是反应性的,但flows
是。
5- livedata
gives you the only latest value what it receives but regular flows
throws values from bucket one by one 5-
livedata
为您提供它接收到的唯一最新值,但regular flows
从存储桶中一一抛出值
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
.您可能已经注意到,我说很多
regular flows
不是flow
,因为还有其他与流程相关的机制,您可以管理 UI state,它们是stateFlow
和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). Stateflow 是
livedata
的替代品,缺点是您必须编写更多代码以使其具有生命周期意识,因为它不是预构建的,并且 stateflow 始终为您提供在配置更改或屏幕切换(片段导航)期间持续存在的最后一个值。
sharedFlows
is good for managing the one time event like toastMsgs, snackbar etc. sharedFlow
was actually the replacement of BroadcastChannels
. sharedFlows
非常适合管理一次性事件,例如 toastMsgs、snackbar 等。 sharedFlow
实际上是BroadcastChannels
的替代品。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.