从 Android 中的视图传回事件的正确方法

Correct way to pass events back from a view in Android

我一直在遵循本文 https://developer.android.com/jetpack/guide/ui-layer 中列出的 UI 体系结构,其本质上相当于:

效果很好,但是文章中没有给出如何将事件从 UI 元素传回 ViewModel 的示例(例如在 onclick 事件的情况下)。

我的 MainActivity 中有以下代码:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val loginViewModel: LoginViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val loginView = LoginView(layoutInflater)
        setContentView(loginView)
    }

    fun setContentView(iView: IView) {
        super.setContentView(iView.contentView)
    }
}

我可以轻松地向 LoginView 添加一些内容,例如 LoginView.setOnSubmitClickedListener(),然后从 MainActivity 在我的 ViewModel 中触发一个事件。我只是想知道这是否是正确的方法,或者是否有更好的方法?

它在关于单向数据流的部分中进一步深入 - 或者有 a separate article on events(您正在查看概述页面)

这是他们使用的示例:

class LatestNewsActivity : AppCompatActivity() {

    private lateinit var binding: ActivityLatestNewsBinding
    private val viewModel: LatestNewsViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        /* ... */

        // The expand section event is processed by the UI that
        // modifies a View's internal state.
        binding.expandButton.setOnClickListener {
            binding.expandedSection.visibility = View.VISIBLE
        }

        // The refresh event is processed by the ViewModel that is in charge
        // of the business logic.
        binding.refreshButton.setOnClickListener {
            viewModel.refreshNews()
        }
    }
}

那里有两种事件 - 一种纯粹是关于 UI(无论是否扩展了它的一部分),另一种实际上以某种方式与基础数据相关。

ViewModel 不需要关心 UI 状态,因此直接在 UI 中处理。但是当涉及到刷新数据时,他们会调用 ViewModel 本身的处理函数。并且由于观察者模式,如果该事件导致 VM 中的数据发生某些变化,观察者将看到它并更新 UI 作为响应。

所以您实际上并没有直接更新 UI 来响应事件!您更新虚拟机,UI 将根据所有内容的连接方式自行更新。

在您的视图模型中 class 创建一个 public 函数,例如

fun onButtonClick() {
    //do something
}

并在 xml 中使用 mvvm 数据绑定导入您的视图模型并附加此函数。您还应该查看绑定适配器以供参考。

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

<data>
    <import type="android.view.View" />
    <variable
        name="viewmodel"
        type="com.invotyx.onta.auth.fragment.login.LoginVM" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content">

<androidx.appcompat.widget.AppCompatButton
     android:id="@+id/btn_sign_in"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"

         android:onClick="@{()-> viewmodel.onButtonClick()}"

     android:text="@string/sign_in" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

你可以了解更多关于它的信息here 或者坦率地说任何其他 mvvm 综合文章