Android MVVM UI控制

4
我开始学习在Android上使用MVVM和LiveData。我认为显示和更新基本数据对我来说很清楚。但我在寻找最佳实践方面遇到了麻烦,即控制UI的问题。
假设我有一个基本的UI,例如一个表单。它有几个EditTextViews用于输入数据。最后还有一个开关。如果它是“ON”,则会显示更多的EditTextViews以供填写。当它处于“OFF”状态时,它们就消失了。
我的问题是在哪里实现这个逻辑?
1. 在Activity/Fragment代码中?这样业务逻辑将涉及到MVVM的VIEW部分(我觉得这不太好)。 2. 在ViewModel中?那么业务逻辑将存在于“数据缓存”中。这样,我需要在ViewModel中创建一堆布尔值获取器,以计算各个View可见性的值。然后在我的Activity中,在LiveData更改的订阅块中,我需要逐个读取所有这些值并设置视图的可见性。 3. 在一个单独的Service/Helper/Util类中?这将是与#2相同的解决方案,只是从ViewModel中提取了逻辑。
这里应该采用什么最佳实践?尽管如此,这个问题可能也会在用户输入验证方面出现(我想这些领域有很多这样的问题)。

开/关状态是否影响除UI可见性之外的其他内容?如果没有UI,它在业务逻辑中的作用是什么? - Stachu
当它开启时,业务逻辑将依次填充POJO中的字段;当它关闭时,相同的字段则被留空/清除。例如,如果“未成年”开关打开,则用户必须输入法定代表人的数据(如母亲姓名等),并且这些数据需要保存。 - Mordred
据我理解,它是由UI驱动的(用户点击按钮),而不是从其他POJO属性派生的,例如出生日期与现在的日期?如果用户打开按钮,填写字段并关闭它,则无论UI中的字段是否为空,POJO都应该具有空值,对吗? - Stachu
正确。是的,我现在知道这个例子不是最好的。根据出生日期和当前日期计算未成年人在大多数情况下是必要的,正如你所提到的。这只是一个快速的示例,说明有时需要显示一些UI组件,有时则需要隐藏它们。 - Mordred
1个回答

0
我会选择第二种方法,但是稍微不同的实现方式(使用DataBinding),受到Google的样例Sunflower应用程序的启发: https://github.com/android/sunflower 它旨在介绍Jetpack最佳实践,包括MVVM。
在LiveData更改的订阅块中,我需要读取所有这些值并逐个设置视图的可见性。与其这样做,你可以将你的布局订阅到ViewModel(使用DataBinding),类似于这样: https://github.com/android/sunflower/blob/master/app/src/main/res/layout/fragment_plant_detail.xml
    <data>
        <import type="com.google.samples.apps.sunflower.data.Plant"/>
        <variable
            name="viewModel"
            type="com.google.samples.apps.sunflower.viewmodels.PlantDetailViewModel" />
    </data>

然后,根据对ViewModel的引用(不使用getter方法),在布局本身中设置可见性

app:isGone="@{!viewModel.isUnderAge}"

或者

android:visibility="@{viewModel.isUnderAge?  View.VISIBLE : View.INVISIBLE}"

说实话,如果可能的话,我会避免使用DataBinding。我有两个原因:
  • 就像我在原问题的第一个选项中所说的那样,这会将业务逻辑放入应用程序的VIEW层。
  • 当你将代码写入string并让后台架构将其作为代码执行时,我通常不喜欢这种解决方案。如果一切看起来都很好(没有拼写错误、编译问题等),正确的功能就会发生。我会尽可能避免它,因为它真的违背了我的源代码口味。
- Mordred
阅读此文章,了解为什么数据绑定是危险的:https://medium.com/@hellotimmutton/an-argument-against-data-binding-13e2aaf7a9b1 - Mordred
我之前已经阅读过这篇文章,虽然我同意关注点分离的重要性,但我不同意他的解释。模型应该能够与任何附加的UI一起工作,因此例如android:visibility=”@{viewModel.showTitle ? View.VISIBLE : View.GONE}”是一个糟糕的例子 - 它描述了UI状态,而不是业务逻辑状态。如果在业务逻辑中有一种状态,你希望不显示标题,则添加反映该状态的可观察对象,并让UI对其做出反应(例如通过隐藏标题和其他一些视图 - 这就是我在Fragment或数据绑定中所做的)。 - Stachu
我会按照我们讨论的方式使用#2方法,但尝试使用LiveData。 - Mordred

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接