【问题标题】:Send data from repository to view model in MVVM architecture将数据从存储库发送到 MVVM 架构中的视图模型
【发布时间】:2023-03-09 02:11:01
【问题描述】:

我对使用 MVVM 架构感到困惑!在某些教程中,LiveData 存储在存储库中,然后传递给ViewModel。在许多其他情况下,LiveData 是在存储库的函数中定义的,并使用函数的结果传递给ViewModel。但是Google says:

在您的数据层类中使用 LiveData 对象可能很诱人,但 LiveData 并非旨在处理异步数据流。 ........ 如果您需要在应用程序的其他层中使用数据流,请考虑使用 Kotlin Flows,然后使用 asLiveData() 在 ViewModel 中将它们转换为 LiveData。 .... 对于使用 Java 构建的代码库,请考虑将 Executors 与回调或 RxJava 结合使用。

我更喜欢使用 Kotlin coroutinesFlows。但我不知道在我的情况下是否真的需要。我正在开发一个聊天应用程序。当接收到消息时,将在存储库中调用侦听器并在其中接收消息数据。 (监听器在后台线程中运行)现在我想将消息对象发送到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)
}
}

我可以使用高阶函数轻松做到这一点:

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)
}
}

但是使用 Kotlin 是 coroutines 还是 Flows 更好?在某些类似的情况下,需要将列表发送到ViewModel

【问题讨论】:

    标签: android kotlin mvvm kotlin-coroutines android-livedata


    【解决方案1】:

    我可以使用高阶函数轻松做到这一点。

    是的,这是一个回调,您可以使用它来通知ViewModel 新消息。 Kotlin 协程有助于避免回调并具有顺序代码。

    在您的情况下,onMessage 是热数据流,我们可以使用 SharedFlow 将其转换为热 Flow

    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)
    }
    

    如果需要,在ViewModel 中使用asLiveData 方法很容易将其转换为LiveData

    ChatsRepo.messagesFlow.asLiveData()
    

    依赖使用asLiveData()扩展函数:

    def lifecycle_version = "2.4.0"
    
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
    

    【讨论】:

    • 这种情况下,使用Flow的好处仅仅是避免回调?我知道使用协程代替线程在后台执行部分代码具有更好的性能。但是 onMessage 在已经创建的线程上运行。使用 Flow 代替回调会提高性能吗?
    • 您能解释一下什么是 extraBufferCapacity 以及为什么将其值设置为 64?
    • @hyapp 我认为在这种情况下使用 Flow 不会以某种方式提高性能。
    • @HusseinYaqoobi extraBufferCapacity 是一些对象,如果消费者比生产者慢,可以缓冲这些对象。它可以是任何数字,具体取决于具体情况,甚至,如果我没记错的话,是无穷大,但在后一种情况下,您可以获得 OutOfNemoryException。
    【解决方案2】:

    Livedata 从来都不是为响应式流设计的,它一直是为 last layer (viewmodel to view) 设计的,当 livedata 与改造(使用 calladapter)和房间(谷歌做到了)一起使用时,有/有解决方法。
    而现在由于协程的兴起推荐的方式是在处理业务逻辑的时候使用kotlin Flows但是需要注意的事情:
    1- regular flow 不是可观察的,但 livedata 是可观察的。
    2- 使用 regular flows 管理 UI 状态并不好,但您可以使用 livedata 来管理。
    3- livedata 是lifecycle aware,但流不是。
    4- livedata 不是反应性的,但flows 是反应性的。
    5- livedata 为您提供它接收到的唯一最新值,但 regular flows 从存储桶中一个一个地抛出值

    您可能已经注意到我说了很多regular flows 而不是flow 因为还有其他与流程相关的机制,您可以管理stateFlowsharedFlow 的UI 状态。
    Stateflow 是 livedata 的替代品,缺点是您必须编写更多代码以使其具有生命周期意识,因为它不是预构建的,并且 stateflow 始终为您提供它在配置更改或屏幕切换期间持续存在的最后一个值(片段导航) .
    sharedFlows 非常适合管理一次性事件,例如 toastMsgs、snackbar 等。sharedFlow 实际上是 BroadcastChannels 的替代品。

    【讨论】:

      【解决方案3】:

      如果你是 Rxjava 高手,我不建议你使用 flow/livedata。我认为 flow/livedata 是为 UI Reactive 而设计的,而不是为底层数据转换而设计的。所以你可以在data repository中使用rxjava,在viewmodel中可以将其转换为livedata并使用。

      【讨论】:

      • Flow 中没有任何内容表明它是“为 UI 设计的”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-27
      • 2018-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多