一.几种常见架构模式简介

MVC架构:

M指的是Model,数据模型;

V指的是界面,一般是xml布局,或者有些界面我们直接使用代码书写的,所以也包含Activity和Fragment;

C指的是Controller,控制逻辑,一般控制逻辑都在Activity,Fragment中。

优点:

把逻辑拆分开,避免耦合。

缺点:

我们通过上面的简单介绍就可以看到一些问题,首先Activity,Fragment担当的职责过多,违背职责单一原则。实际应用中,MVC架构下的Activity,Fragment代码往往几千行,极其臃肿。

MVP架构:

M指的是Model,还是数据模型;

V指的是IView,视图逻辑接口,而不是单纯的视图了;

P指的Presenter,向导交流中心,处理核心逻辑。

我们也总结一下MVP的优点和缺点:

优点:

1.完全的解耦。其原因是我们是面向接口编程的,职责十分清晰,属于设计上的依赖倒置。

2.Presenter和Model是可以复用的。单纯的界面变化,我们只需要修改IView的实现即可。

3.由于相互之间是完全解耦的,所以可以针对M,V,P分开单独测试。

4.三者之间相互不耦合,所以方便后续扩展和升级。

缺点:

1.面向接口编程,所以各种界面渲染场景比较多的时候,会造成接口爆炸的问题。

2.接口升级时,不单单要修改实现类,有时甚至需要修改接口。

MVVM架构:

M指的是Model,仍然是数据模型;

V指的是View,视图;

VM指得是ViewModel,属于关联视图和Model的。View和Model相互不关联,通过ViewModel进行双向绑定。修改Model后,View则对应发生变化。

优点:

1.代码书写上的简洁。因为代码中少了setText这样的代码。

2.职责的清晰。相关的业务逻辑都在每个ViewModel中,不同的ViewModel承担不同的了逻辑。

3.针对数据的改变会自动反馈到界面上,使用起来会方便的多。

缺点:

缺点这块也是个人的见解。

1.因为数据数双向自动绑定的,所以监控到底是哪个ViewModel最终去修改的text值变的困难。当然,可以通过监控数据的改变来解决这问题。

小结:

MVC和MVP都属于命令式的UI,所以都需要找到一个需要设置的对象,比如setText,setBackground等等。

而MVVM和MVI属于声明式UI,只需要修改对应的参数,而不需要给到被设置的对象,所以在前端交互上,会让我们感觉到更便捷。

二.MVI架构

MVI架构是面向意图编程,我们把各种诉求转化为一个个的意图,请求列表数据是一个意图,请求详细信息也是一个意图。

M:ViewModel,指的是可以被观测数据;

V:View,指的是视图;

I:Intent,指的是意图,比如获取列表数据,获取详情搜索数据等。

具体流程我们可以用下面这张图来概括:

三.使用MVI架构来写Compose

接下来,我们会按照上面图中的顺序,一步一步的来使用MVI框架编写一个完整的界面流程。

首先.我们先引入Compose框架。创建MVIComposeActivity。

ContentViewModel的话不着急,这一步只要先创建一个ContentViewModel的类即可。

class MVIComposeActivity : ComponentActivity() {private val viewModel by viewModels<ContentViewModel>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ContentView(viewModel)}}
}

接下来,我们就要开始构建我们的意图了。

ContentViewModel中,构建我们的意图,目前先定义两个,获取列表和获取详情。

sealed class ContentIntent {//传递消息object GetContent : ContentIntent()class GetItemDetail(val select: Int) : ContentIntent()
}

这里肯定有人会问,为什么一个是object类型,一个class类型。因为第二个是带参数的,所以每次都需要重新构建一个意图,而第一个无参,则复用同一个就可以了。

第三步,我们来构建ViewModel

创建信道newsChannel。信道来接受各种用户行为发过来的意图。

创建状态管理uiState,由其完成数据的绑定。

最后在初始化的时候,进行意图和获取数据的关系绑定(handleIntent方法)。

class ContentViewModel : ViewModel() {//Channel信道,意图发送别ViewModel,val newsChannel = Channel<ContentIntent>(Channel.UNLIMITED)//状态管理var uiState by mutableStateOf(NaviViewState())init {handleIntent()}private fun handleIntent() {viewModelScope.launch {newsChannel.consumeAsFlow().collect() {when (it) {is ContentIntent.GetContent -> getContent()is ContentIntent.GetItemDetail -> getNewsDetail(it);}}}}private val newsFlow: Flow<List<String>> = flow {val list = mutableListOf<String>()list.add("111")list.add("222")emit(list)}private val detailFlow: Flow<List<String>> = flow {val list = mutableListOf<String>()list.add("111-详情")list.add("222-详情")emit(list)}private fun getContent() {viewModelScope.launch {newsFlow.flowOn(Dispatchers.Default).collect { contents ->uiState = uiState.copy(dataList = contents)}}}private fun getNewsDetail(select: ContentIntent.GetItemDetail) {viewModelScope.launch {detailFlow.flowOn(Dispatchers.Default).collect { contents ->uiState = uiState.copy(detailContent = contents[select.select])}}}
}

第四步,回过头来,我们进入到View的流程。

进入到页面后,首先进行的意图是请求所有数据。

@Composable
fun ContentView(viewModel: ContentViewModel) {//请求数据val viewState = viewModel.uiState//请求数据的意图LaunchedEffect(key1 = true) {viewModel.newsChannel.send(ContentIntent.GetContent)}//数据与View的绑定Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {viewState.dataList!!.forEachIndexed { index, it ->NewsItem(viewModel, position = index, news = it)}}viewState.detailContent?.let {ToastUtil.showCenterToast(it)}
}

则此时我们上一步中构造的handleIntent方法中的newsChannel就会收到这个意图,并进行对应的处理:

private fun handleIntent() {viewModelScope.launch {newsChannel.consumeAsFlow().collect {when (it) {is ContentIntent.GetContent -> getContent()//这里进行处理is ContentIntent.GetItemDetail -> getNewsDetail(it);}}}}

getContent方法中去请求数据(这里可以进行网络请求,我这里就不进行了),返回结果后,把数据绑定到uiState上。

 private fun getContent() {viewModelScope.launch {newsFlow.flowOn(Dispatchers.Default).collect { contents ->uiState = uiState.copy(dataList = contents)}}}

至此,流程上就结束了。MVI架构下,我们只需要修改uiState就可以了。

完整代码地址:

android_all_demo/MVIComposeActivity.kt at master · aa5279aa/android_all_demo · GitHub

Compose实战-以MVI的方式写Compose相关推荐

  1. 使用Compose实现基于MVI架构、retrofit2、支持 glance 小部件的TODO应用

    前言 现在声明式 UI 已逐渐成为主流,在客户端上,已有成熟的 Flutter 和 SwiftUi ,而原生安卓上的声明式 UI 却在去年年底才姗姗来迟. 虽然 compose 姗姗来迟,但是关于它的 ...

  2. Docker技术入门与实战 第二版-学习笔记-9-Docker Compose 项目-2-Compose 命令说明

    Compose 命令说明 1)命令对象与格式 对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中 的服务或者容器.如果没有特别的说明,命令对象将是项目,这意味着项目中所有 ...

  3. Compose Multiplatform结合MVI模式--初步尝试

    写了个简单的界面,包含功能: 1,列表中动态增加行和删除行 2,根据列表中的数据生成 json. 包含的文件或类: 1,Main.kt, 程序入口,使用 Window 即是 desktop 端. 2, ...

  4. 【卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10)】

    卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10) 在上一章已经完成了卷积神经网络的结构分析,并通过各个模块理解 ...

  5. rest风格使用两个变量_为什么要用Rest风格,接口应该怎么定义,除了Rest还可用什么方式写接口的?...

    这里是修真院后端小课堂,每篇分享文从 深度思考中的知识点--为什么要用Rest风格,如果不用Rest的话,接口应该怎么定义,在使用Rest风格之前,大家都是用什么方式写接口的? 1.背景介绍 REST ...

  6. 深度学习实战——利用卷积神经网络对手写数字二值图像分类(附代码)

    系列文章目录 深度学习实战--利用卷积神经网络对手写数字二值图像分类(附代码) 目录 系列文章目录 前言 一.案例需求 二.MATLAB算法实现 三.MATLAB源代码 参考文献 前言 本案例利用MA ...

  7. Pytorch实战1:LeNet手写数字识别 (MNIST数据集)

    版权说明:此文章为本人原创内容,转载请注明出处,谢谢合作! Pytorch实战1:LeNet手写数字识别 (MNIST数据集) 实验环境: Pytorch 0.4.0 torchvision 0.2. ...

  8. javascript 编码规范 用更合理的方式写 javascript

    目录 类型 引用 对象 数组 解构 Strings 函数 箭头函数 构造器 模块 Iterators and Generators 属性 变量 Hoisting 比较运算符和等号 代码块 注释 空白 ...

  9. JavaScript--------------------jQuery中.bind() .live() .delegate() .on()的区别 和 三种方式写光棒事件 动画...

    bind(type,[data],fn) 为每个匹配元素的特定事件绑定事件处理函数. $("a").bind("click",function(){alert( ...

最新文章

  1. android平板 2017,2017年后平板电脑市场将复苏
  2. 面试的时候的要注意的case应该怎么分析
  3. 预告 | 旷视天元的前世今生与移动端推理优化@清华专场
  4. oracle千万级分页优化,oracle千万级数据分页存储过程优化
  5. jzoj1166-树中点对距离【点分治】
  6. 【语音去噪】基于matlab小波软阈值语音降噪【含Matlab源码 531期】
  7. java数据库连接access_java连接Access数据库的方法
  8. Qt优秀开源项目之十四:SortFilterProxyModel
  9. “用户体验及可用性测试”前三章:读书笔记
  10. python排名上升_11点告诉你,Python为什么这些年在编程语言排行榜上一直上升?...
  11. 2022Java学习笔记八十八(网络编程:UDP通信,一发一收,多发多收消息接收实现)
  12. qt creator 32位linux,Qt Creator下载mac版-Qt Creator Mac版下载 V4.14.2-PC6苹果网
  13. xshow-1. 项目简介
  14. 100人坐飞机,第一个乘客在座位中随便选一个坐下,第100人正确坐到自己坐位的概率是?
  15. 斯图飞腾Stratifyd发布《2021金融服务行业客户体验报告》
  16. 【c++】vector中删除元素
  17. 能阅读计算机英语,全阅读英语电脑版
  18. C#-数组截取的方法
  19. Django ckeditor自定义表情包
  20. 基于钣金工艺优化的钣金件结构设计

热门文章

  1. IUV“经世杯”option3X
  2. Linux 时间、时区设置
  3. 【项目一、xxx病虫害检测项目】1、SSD原理和源码分析
  4. mongodb 跟踪SQL语句及慢查询收集
  5. Converting Phase Noise to Time Jitter
  6. 用计算机弹生僻字乐谱,抖音生僻字计算器乐谱 抖音生僻字计算器数字简谱
  7. 【学习笔记】builtin函数
  8. JAVA操作execl
  9. python-字符串连接
  10. linux 怎么看节点核数,Linux怎么查看CPU核数?-linux运维