ViewModel和LiveData:模式+反模式翻译

分配职责

应用架构组件中典型的实体交互
应用架构组件中典型的实体交互
理想情况下,ViewModels 不应该对Android框架类有耦合。这提高了可测试性、泄漏安全性和模块性。一般的经验法则是确保你的ViewModels 中没有导入像 android.( android.arch. 例外)。presenters也一样。
不要让ViewModels(和 Presenters)知道Android框架类的存在
条件语句、循环和业务逻辑应该在ViewModels或应用程序的其他层中进行,而不是在Activity 或 Fragment中进行。View层通常不可单元测试(除非使用Robolectric),所以代码行越少越好。View层只应该知道如何显示数据并将用户事件发送到ViewModel(或Presenter)。这被称为被动视图模式。
把Activity 或 Fragment中的逻辑保持到最少

ViewModel的视图引用

ViewModel具有不同于Activity的作用域。当ViewModel处于活动状态并运行时,Activity可以处于任何生命周期。在ViewModel不知道的情况下,Activity和Fragment可能被销毁和再次创建。
配置更改时ViewModel持续存在
配置更改时ViewModel持续存在
将View(Activity 或 Fragment)的引用传递给ViewModel有严重的风险。假设ViewModel请求来自网络的数据,数据稍后回来。此时,引用的视图可能被销毁,或者可能是不再可见的旧Activity,从而产生内存泄漏,并且可能导致崩溃。
避免在ViewModel中引用View
在ViewModels和Views之间进行通信的推荐方式是观察者模式,使用LiveData或其他库。

观察者模式

这里写图片描述
在Android中设计Presenter 层的一个非常方便的方法是让View(Activity 或 Fragment)观察(订阅更改)ViewModel。由于ViewModel不需知道Android,它不知道Android是如何频繁地杀掉视图的。这样有一些优点:

  1. ViewModel在配置更改时保持不变,因此当发生旋转时,不需要重新查询外部数据源(例如数据库或网络)。
  2. 当长时间运行的操作完成时,ViewModel中的可观测项被更新。不管数据是否被观察,都不重要。当试图更新不存在的视图时,不会出现空指针异常。
  3. ViewModel不引用视图,因此内存泄漏的风险更小。
 private void subscribeToModel() {
  // Observe product data
  viewModel.getObservableProduct().observe(this, new Observer<Product>() {
      @Override
      public void onChanged(@Nullable Product product) {
        mTitle.setText(product.title);
      }
  });
}

典型的订阅代码
让UI观察到它的变化,而不是将数据推到UI上

臃肿的ViewModel

如果你的ViewModel持有太多代码或太多的责任,考虑:

  • 将一些逻辑移到presenter,与ViewModel具有相同的范围。它将与应用程序的其他部分进行通信,并更新ViewModel中的LiveData。
  • 增加一个Domain 层,采用了清晰的体系结构。这构成一个非常可测试和可维护的体系结构。

分配职责,如果需要的话添加domain 层

使用数据仓库

正如在 Guide to App Architecture 中看到的,大多数应用程序都有多个数据源,如:
远程:网络还是云
本地:数据库或文件
内存缓存
如果有多功能的且非常不同的数据模型,考虑添加多功能的存储库。

数据状态处理

考虑这个场景:你正在观察一个LiveData ,它包含一个要显示的列表。视图如何在加载数据、网络错误和空列表之间进行区分?
可以从ViewModel中公开LiveData < MyDataState>。例如,MyDataState可以包含有关数据是否正在加载、已加载成功或失败的信息。
这里写图片描述
使用包装或另一个LiveData 公开有关数据状态的信息

保存Activity状态

Activity状态是如果一个Activity消失了,即该活动被销毁或进程被终止,则需要重新创建屏幕的信息。旋转是最明显的情况,我们已经看到了ViewModel。状态是安全的,如果它是保存在ViewModel。
然而,在其他ViewModel也消失的场景中,您可能需要恢复状态:例如,当OS资源不足并终止进程时。
为了有效地保存和恢复UI状态,使用持久性、onSaveInstanceState()和ViewModel的组合。请参阅:ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders

ViewModel泄漏

这里写图片描述
UI层使用观察者模式,数据层使用回调
如果用户退出应用程序,View将消失,因此不再观察ViewModel 。如果数据仓库是单例,或者以其他方式限制应用程序的范围,则数据仓库将不会被销毁,直到进程被终止。只有当系统需要资源或用户手动杀死应用程序时才会终止。如果数据仓库中持有对ViewModel 回调的引用,则ViewModel 将暂时泄漏。
这里写图片描述
Activity关闭,但ViewModel 仍在
理想情况下,当没有任何观察者,ViewModel都应该自由地销毁:
这里写图片描述
有很多选择来实现这一点:

  1. 使用ViewModel.onCleared(),可以告诉数据层删除ViewModel回调。
  2. 在数据层中,使用弱引用,或者使用事件总线(容易误用,甚至被认为有害)。
  3. 使用LiveData在数据层和ViewModel之间进行通信,就像在View和ViewModel之间使用LiveData一样。

考虑边缘情况、漏洞以及长时间运行的操作如何影响体系结构中的实例。
不要把逻辑放在ViewModel,这对于保存状态清晰或数据相关至关重要。

数据层中的LiveData

为了避免泄露ViewModel和回调地狱,可以像这样观察数据层:
这里写图片描述
当ViewModel被清除或View生命周期结束时,订阅被清除:
这里写图片描述
每当你需要一个ViewModel内的生命周期对象时,Transformation可能是解决方案。

扩展LiveData

LiveData最常见的用例是在ViewModel中使用MutableLiveData ,并将它们暴露为LiveData,以使它们不受观察者的影响。
如果你需要更多的功能,扩展LiveData可知道什么时候有活跃的观察者。例如,当想开始侦听位置或传感器服务时,这是有用的。

public class MyLiveData extends LiveData<MyData> {

    public MyLiveData(Context context) {
        // Initialize service
    }

    @Override
    protected void onActive() {
        // Start listening
    }

    @Override
    protected void onInactive() {
        // Stop listening
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值