简体   繁体   English

从存储库发送数据以查看 MVVM 架构中的 model

[英]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 coroutinesFlows 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,它们是stateFlowsharedFlow
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.

相关问题 从MVVM体系结构中的存储库中插入数据后,无法切换到MainActivity - Unable to switch to MainActivity after data insertion from repository in MVVM architecture 在 MVVM 架构中,视图 model 是否应该只将 Live 数据返回给片段? - In MVVM architecture, should the view model only return Live data to fragment? 如何在Android的MVVM架构中将动作从View发送到ViewModel - How to send actions from View to ViewModel in MVVM architecture in Android Jetpack中的View模型与MVVM体系结构中的视图模型相同吗? - Is View model in jetpack is same as view model in MVVM architecture? 在 Android MVVM 架构上,是否有一种通用的方法可以定期从服务器同步/拉取远程存储库数据? - Is there a common way to sync/pull a remote repository data from server regularly on the Android MVVM architecture? MVVM从模型到存储库的返回值 - MVVM return value from Model to Repository 使用架构组件 MVVM 进行身份验证,将令牌从 Repository 传递到 ViewModel - Authentication with Architecture Components MVVM, passing token from Repository to ViewModel 具有自定义视图的 MVVM 架构 - MVVM architecture with custom view 使用MVVM体系结构从FireStore检索数据 - Retrieving Data from FireStore using MVVM Architecture 如何在 MVVM 架构中使用来自 onActivityResult 的数据? - How to use data from onActivityResult in MVVM architecture?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM