从 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 综合文章
我一直在遵循本文 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 综合文章