对于具有多个字段的活动,应如何实现ViewModel

时间:2018-07-12 13:42:38

标签: android mvvm architecture android-architecture-components android-livedata

问题

有一个设置屏幕(SettingsActivity),其中包含约10个文本字段和3个按钮。文本字段在onClick上打开一个对话框来插入/编辑文本,其内容保存在SharedPreferences中。这些按钮执行异步请求以检索内容并将其保存在其他位置。在请求期间,将显示一个对话框通知进度。

初始解决方案

DataRepository

基本上是SharedPreferences的包装,它具有10个getter和10 setter,每个字段一个。在get[field_name]上,DataRepositorySharedPreferences获取值,在set[field_name]上,它提交给SharedPreferences

ViewModel

一个ViewModel,其中有10个MutableLiveData对象,每个字段一个。此类实现LifecycleObserver来了解SettingsActivity的生命周期,因此可以从onCreate上的存储库中加载字段,并将字段保存到onDestroy上的存储库中。

还有3种方法来执行由3个按钮触发的3个异步请求。每个方法都接收一个OnRequestProgressListener实例,该实例将传递到发出异步请求的类,该异步请求用于将视图通知进度。

查看

具有10个字段的活动,该活动观察MutableLiveData中的10个ViewModel。在每个字段的onClick上,打开一个对话框来编辑/插入文本。在对话框的onPositiveButton上,将调用相应字段的观察者。

该活动实现了OnRequestProgressListener,以根据异步请求的进度显示和隐藏对话框。

最初的解决问题

上述设计似乎不正确。我可以指出一些:

    MutableLiveData
  • 10 ViewModel
  • DataRepository
  • 10个getter和10个setter;
  • SharedPreferences的存储库。
  • ViewModel接收侦听器,以传递给执行异步请求的类,这些请求使用这些侦听器来通知视图。全部位于ViewModel中间。

正确的解决方案

这是正确的解决方案吗?如果不是,我认为不是,应该如何设计正确的解决方案?

2 个答案:

答案 0 :(得分:3)

  
      
  • ViewModel中有10个MutableLiveData;
  •   

很好,如果您有10个独立的数据,则每个数据都有一个LiveData。

  
      
  • SharedPreferences的存储库。
  •   

存储库应该是数据层的抽象,从而使您可以轻松切换实现。因此,从理论上讲,可以在共享首选项上拥有一个存储库。

但是在您的情况下,如果存储库唯一要做的就是将调用转发到SharedPreferences,因为将存储解决方案从共享首选项切换到其他资源的可能性非常低,那么我将摆脱存储库并使用直接使用SharedPreferences可以简化代码。

  
      
  • DataRepository中的10个getter和10个setter;
  •   

同样,如果您的类中存储了10条数据,并且希望从外部访问这些数据,则应使用属性模式,这将导致Java中的getter和setter方法。在Kotlin中,尽管您不需要显式编写getter和setter。 另外,如果您决定删除DataRepository,则不需要该代码。

  
      
  • ViewModel接收侦听器,以传递给执行异步请求的类,这些请求使用这些侦听器来通知视图。全部位于中间的ViewModel。
  •   

这听起来有些不对劲,如果您在活动中创建了一个侦听器,则可能会偶然使用引用活动的匿名类,将其传递给ViewModel并导致内存泄漏。 您不应将活动引用传递给ViewModel。 正确的通信方式是通过LiveData。您需要创建一个将发布进度的LiveData,在ViewModel中使用它,并为其提供进度,并且您的活动需要订阅它才能获取进度信息。 使用这种方法,您可以避免内存泄漏。

答案 1 :(得分:1)

您可以使用一个Settings数据类,其中包含封装您的数据的字符串,整数和获取器。

一个MutableLiveData<Settings>足以跟踪更改并将更改传递到UI。如果使用TextViews和EditTexts,则使用数据绑定也不需要样板代码。要使数据绑定与LiveData一起使用,您需要使用setValue()中定义的方法来调用LiveData中的ViewModel。我做了an example的数据绑定是如何工作的,而不是LiveData的工作。

您可以查看my answer,了解如何使用具有可变对象的LiveData并更新UI,而无需任何锅炉代码和不必要的MutableLiveDatas或将MutableLiveData<Object>转换为MutableLiveData<String>或{ {1}}。

如果您可以共享布局文件,我可以发布更具体的答案。