当前位置: 首页 > news >正文

Android Jetpack系列之MVI架构

文章目录

      • 写在前面
      • MVI vs MVVM
        • 新旧架构对比
        • 差异1、LiveData < T> 改为Flow< UIState>
        • 差异2、View与ViewModel的交互规范
      • 总结
      • 资料

写在前面

在之前介绍MVVM的文章中,介绍了常用的MVC、MVP、MVVM架构及其对MVVM的封装使用,其中MVVM的主旨可以理解为数据驱动:Repository提供数据,ViewModel中发送数据,UI层使用的LiveData订阅数据,当有数据变化时会主动通知UI层进行刷新。有兴趣的可以去看一下:

1、 Android Jetpack系列之MVVM使用及封装
2、Android Jetpack系列之MVVM使用及封装(续)

那么MVI又是什么呢?看了一些关于MVI的文章,大家都称MVI是(Model-View-Intent),其中Intent称为意图(注意这里的Intent并不是页面跳转时使用的Intent),MVI本质上是在MVVM的基础上将ViewViewModel之间的数据传递做了统一整合

google官方文档中并没有MVI的说法,而是在之前的MVVM架构基础上进行了升级,其主旨意思与MVI很相近,为了保持一致,后续介绍的MVVM升级版架构统一称之为MVI架构。

MVI vs MVVM

新旧架构对比

  • 旧版MVVM架构:
    MVVM

  • 新版MVVM或者称之为MVI
    新版MVVM or 称之为MVI

差异1、LiveData < T> 改为Flow< UIState>

关于LiveData的缺点:

  • LiveData的接收只能在主线程;
  • LiveData发送数据是一次性买卖,不能多次发送;
  • LiveData发送数据的线程是固定的,不能切换线程,setValue/postValue本质上都是在主线程上发送的。当需要来回切换线程时,LiveData就显得无能为力了。

Flow可以完美解决LiveData遇到的问题,既可以多次从上游发送数据,也可以灵活地切换线程,所以切到Flow是更优解。关于Flow的详细用法,感兴趣的同学可以参见:Android Kotlin之Flow数据流

注:如果项目中还没有切换到Kotlin,依然可以使用LiveData来发送数据;如果已经切换到Kotlin,那么更推荐使用Flow来发送数据。

还有一点区别,LiveData在旧版架构中传递的是实体数据,新版架构中通过Flow发送的统一为UIState了。关于UIState,后面在具体示例中再讲解。

差异2、View与ViewModel的交互规范

新版架构中,提出了单向数据流来管理页面状态的概念,即View层请求ViewModel的事件会统一在一起,这样数据传递会集中管控,提高代码的可读性及修改的便利性。单向数据流有以下好处:

  • 数据一致性。界面只有一个可信来源。
  • 可测试性。状态来源是独立的,因此可独立于界面进行测试。
  • 可维护性。状态的更改遵循明确定义的模式,即状态更改是用户事件及其数据拉取来源共同作用的结果。

集中管控有个很大的好处:我们在新版架构中,只需要定义为数不多的几个Flow即可,多个不同请求都可以使用;而使用旧版MVVM时,如果请求的数据很多,那么相应的,我们需要在ViewModel中定义很多的LiveData或者Flow,如下:

 private val _wanFlow = MutableStateFlow<List<WanModel>>(ArrayList())
 val mWanFlow = _wanFlow

其中定义一个可变的Flow,一个不可变的Flow,可变Flow是为了数据的变化,而不可变的Flow是为了防止在View层中改变Flow中的数据,从而破坏单向数据传递。

总结

升级版的MVI架构相比于旧版MVVM架构,规范性更好,约束性也更强。但是并不是说新版的架构就一定适合你的项目,架构毕竟是一种规范,具体使用还需要见仁见智。

资料

【1】 应用架构指南https://developer.android.com/jetpack/guide?hl=zh-cn
【2】界面层架构https://developer.android.com/jetpack/guide/ui-layer?hl=zh-cn#views
【3】界面事件https://developer.android.com/jetpack/guide/ui-layer/events?hl=zh-cn#views

相关文章:

  • 十分钟之内实现stack和queue?容器适配器是什么?priority_queue不是队列?
  • 基于Keras实战项目-猫狗熊猫分类大战
  • 基于 Echarts + Python Flask 动态实时大屏( 附代码)
  • 并查集原理及模拟实现
  • 【Redis】大key的处理
  • T-3.2-把Redis当作消息队列合不合适
  • 简单个人静态HTML网页设计作品 DIV布局个人介绍网页模板代码 DW个人网站制作成品 web网页制作与实现
  • java基于springboot+element的实现医院预约挂号系统 nodejs
  • 在vue项目中使用canvas实现甘特图
  • 【C++】之模板进阶
  • 100天精通Python(数据分析篇)——第58天:Pandas读写数据库(read_sql、to_sql)
  • Bean的生命周期
  • 哈希桶(详解创建)
  • 回归预测 | MATLAB实现SSA-BP多输入单输出回归预测
  • 【雅思备考】听说读写攻略 | 雅思核心词汇之科技类
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • git 常用命令
  • gitlab-ci配置详解(一)
  • hadoop集群管理系统搭建规划说明
  • JavaScript设计模式之工厂模式
  • mysql 5.6 原生Online DDL解析
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • session共享问题解决方案
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • tab.js分享及浏览器兼容性问题汇总
  • vue-router 实现分析
  • 阿里云Kubernetes容器服务上体验Knative
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 聊一聊前端的监控
  • 容器服务kubernetes弹性伸缩高级用法
  • 数据仓库的几种建模方法
  • 数据结构java版之冒泡排序及优化
  • 一个完整Java Web项目背后的密码
  • 栈实现走出迷宫(C++)
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • $.ajax中的eval及dataType
  • $.proxy和$.extend
  • (30)数组元素和与数字和的绝对差
  • (Matlab)使用竞争神经网络实现数据聚类
  • (二)学习JVM —— 垃圾回收机制
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • ***测试-HTTP方法
  • .Net - 类的介绍
  • .net framework4与其client profile版本的区别
  • .Net 代码性能 - (1)
  • .Net8 Blazor 尝鲜
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .NET导入Excel数据
  • @Documented注解的作用
  • [.net] 如何在mail的加入正文显示图片
  • [AutoSar]BSW_OS 02 Autosar OS_STACK
  • [C语言]编译和链接