浅浅的理解MVI

news2024/9/23 1:28:12

MVI 的概念

官网解释:

https://developer.android.google.cn/topic/architecture?hl=zh-cn

  • MVI在架构分层上和MVP没有本质区别,但区别主要体现在架构风格和编程思想上。

  • MVI 是 Model-View-Intent 的缩写,它也是一种响应式 + 流式处理思想的架构。

  • MVI 的 Model 代表一种可订阅的状态模型的概念,添加了 Intent 概念来代表用户行为,采用单向数据流来控制数据流动和各层依赖关系。
    在这里插入图片描述

  • 在代码的层面上它分为三层:
    UI Layer(界面层) :在屏幕上展示应用界面和数据
    Domian Layer(网域层) :封装复杂或可复用的业务逻辑
    Data Layer(数据层) :获取可公开应用数据和完成业务逻辑

  • MVI 中的单项数据流工作流程如下:
    用户操作以 Intent 的形式通知 Model
    Model 基于 Intent 更新 State
    View 接收到 State 变化刷新 UI

MVI - Model-View-Intent

  • MVI是一种响应式和流式的处理思想,将意图事件(用户操作),通过函数转换为特定Model(状态),将其结果反馈给用户(渲染界面)。
  • 抽象下来得到intent(),model(),view() 三个方法
    • intent() 即意图,接收用户的输入(即UI事件,如点击事件)把意图和相关参数封装为数据结构,传递给model()方法。传递意图的接口是统一的,而不像MVP持有Presenter,并调用Presenter的多个接口。
    • model() 不同于一般的model,这里说的model相当于状态模型里的一种状态,model内部的逻辑是不可变的,这能保证状态逻辑的一致性,同时降低系统的复杂性。
    • view() 接收model传来的state渲染UI

在这里插入图片描述

代码案例

在这里插入图片描述

后台接口
/**
 * 时间:2023/5/19
 * @author Mr.Feng
 * 简述: 网络后台接口
 */
interface YaoServiceApi {

    @GET("/banner/json")
    suspend fun getBannerList() : ResponseEntity<List<BannerEntity>>
}
服务器返回类
**
 * 时间:2023/5/19
 * @author Mr.Feng
 * 简述: 服务器返回的封装类
 */
data class ResponseEntity<T>(val errorCode:Int,val data:T,val errorMsg:String)

具体的类
/**
 * 时间:2023/5/19
 * @author Mr.Feng
 * 简述: TODO
 */
data class BannerEntity(
    val desc: String,
    val id: Int,
    val imagePath: String,
    val isVisible: Int,
    val order: Int,
    val title: String,
    val type: Int,
    val url: String
)
网络工具类
	object RetrofitFactory  {
    private val retrofit: Retrofit

    //http://43.143.146.165:7777/banner/json
    init {
        retrofit=Retrofit.Builder()
            .baseUrl("http://43.143.146.165:7777/")
            .addConverterFactory(GsonConverterFactory.create())
//            .addCallAdapterFactory(CoroutineCallAdapterFactory.create)
            .client(createOkHttpClient())
            .build()
    }

    private fun createOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
//            .connectTimeout(TIMEOUT, TimeUnit.SECONDS)
//            .readTimeout(TIMEOUT, TimeUnit.SECONDS)
//            .writeTimeout(TIMEOUT, TimeUnit.SECONDS)
//            .addNetworkInterceptor(createLoggingInterceptor())
            .addInterceptor(createLoggingInterceptor())
//            .addInterceptor(createTokenInterceptor())
//            .addInterceptor(createNormalErrorHttpCodeInterceptor())
            .build()
    }

    private fun createLoggingInterceptor(): Interceptor {
        return HttpLoggingInterceptor().apply { level=HttpLoggingInterceptor.Level.BODY }
    }
    /**
     * create api instance
     */
    fun <T> create(clazz: Class<T>) : T =  retrofit.create(clazz)

仓库类

/**
 * 时间:2023/5/19
 * @author Mr.Feng
 * 简述: 数据层的类
 */
class BannerRepostory @Inject constructor() {

    suspend fun getBannerList(): ResponseEntity<List<BannerEntity>>{
       return RetrofitFactory.create(YaoServiceApi::class.java).getBannerList()
    }
}

意图类

/**
 * 时间:2023/5/19
 * @author Mr.Feng
 * 简述: 意图类,也就是用户要干啥
 */
sealed class BannerIntent {
    object GetBannerList : BannerIntent()
    //举例,可以放多种不的请求,
//    data class GetBannerTitleList(val a:Int) :BannerIntent()
}

状态类

/**
 * 时间:2023/5/19
 * @author Mr.Feng
 * 简述: 状态类,主要对用户的请求的意图是否成功.
 * sealed 是密封类. object是单例,不需要参数  dataclass 构造要参数
 */
sealed class BannerUIState {
    //成功
    data class Success(var banner: ResponseEntity<List<BannerEntity>>): BannerUIState()

    //失败
    data class Fail(var fail:ResponseEntity<List<BannerEntity>>) : BannerUIState()

    //加载中
    object loading: BannerUIState()

    object Init:BannerUIState()
}

viewModel类


@HiltViewModel
/**
 * 时间:2023/5/19
 * @author Mr.Feng
 * 简述: vm类
 */
class BannerViewModel @Inject constructor(private val repostory: BannerRepostory) : ViewModel(){

    val channel = Channel<BannerIntent>(Channel.UNLIMITED)
    //不让外部调用
    private val _state = MutableStateFlow<BannerUIState>(BannerUIState.Init)
    //使用flow来监听
    val state: StateFlow<BannerUIState>
        get() = _state

    init {
        handleIntent()
    }

    //准备处理所有意图
    private fun handleIntent() {
        //起协程准备处理
        viewModelScope.launch {
            channel.consumeAsFlow().collect{
                when(it){
                    is BannerIntent.GetBannerList -> getBannerList()
                }
            }
        }
    }

    private fun getBannerList() {
        viewModelScope.launch {
            val bannerList = repostory.getBannerList()
            if(bannerList.errorCode == 200){
                _state.value = BannerUIState.Success(bannerList)
            }else{
                _state.value = BannerUIState.Fail(bannerList)
            }
        }
    }
//    private fun bannerList() : Flow<ResponseEntity<List<BannerEntity>>> = flow {
//        //发送网络请求
//        val bannerList1 = repostroy.getBannerList()
//        emit(bannerList1)
//    }
}

页面类


@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val veiwmodel: BannerViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lifecycleScope.launch{
            veiwmodel.channel.send(BannerIntent.GetBannerList)
        }

        lifecycleScope.launch {
            veiwmodel.state.collect{
                when(it){
                    is BannerUIState.Success -> {
                        println("成功")
                        println(it.banner.data.size)
                    }
                    is BannerUIState.Fail -> {
                        println("失败")
                    }
                    else -> {
                        println("其他")
                    }
                }
            }
        }
    }
}

启动类

/**
 * 时间:2023/5/20
 * @author Mr.Feng
 * 简述: TODO
 */
@HiltAndroidApp
class MyApp : Application() {
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/547113.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux高级 I/O(2)】如何使用阻塞 I/O 与非阻塞 I/O?——select()函数

上次我们虽然使用非阻塞式 I/O 解决了阻塞式 I/O 情况下并发读取文件所出现的问题&#xff0c;但依然不够完美&#xff0c;使得程序的 CPU 占用率特别高。解决这个问题&#xff0c;就要用到本文将要介绍的 I/O 多路复用方法。 何为 I/O 多路复用 I/O 多路复用&#xff08;IO m…

数据结构-时间复杂度和空间复杂度

时间复杂度和空间复杂度 算法效率时间复杂度空间复杂度表示方法&#xff08;大O的线性表示&#xff09;举例说明时间复杂度举例说明空间复杂度举例说明冒泡排序的时间和空间复杂度递归情况下的时间和空间复杂度两个例子 算法效率 算法&#xff08;Algorithn&#xff09;是指用来…

Spring MVC的核心类和注解

DispatcherServlet DispatcherServlet作用 DispatcherServlet是Spring MVC的核心类&#xff0c;也是Spring MVC的流程控制中心&#xff0c;也称为Spring MVC的前端控制器&#xff0c;它可以拦截客户端的请求。拦截客户端请求之后&#xff0c;DispatcherServlet会根据具体规则…

chatgpt赋能Python-python3接口自动化

Python3接口自动化&#xff1a;提升测试效率的利器 Python是一种高级编程语言&#xff0c;广泛应用于Web开发、数据科学、机器学习等领域。近年来&#xff0c;Python在接口自动化测试领域也变得越来越受欢迎。 Python的易读性、可扩展性以及模块化的特性&#xff0c;使得它成为…

Elasticsearch环境搭建(Windows)

一、介绍 布式、RESTful 风格的搜索和分析。 Elasticsearch 是位于 Elastic Stack 核心的分布式搜索和分析引擎。Logstash 和 Beats 有助于收集、聚合和丰富您的数据并将其存储在 Elasticsearch 中。Kibana 使您能够以交互方式探索、可视化和分享对数据的见解&#xff0c;并管…

手撕code(1)—— 排序算法

文章目录 前言1 冒泡排序2 选择排序3 插入排序4 快速排序5 归并排序6 堆排序7 希尔排序 前言 算法动画 时间复杂度分析 从小到大排序 1 冒泡排序 被动的将最大值送到最右边 1、比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 2、对每一对相邻元素作同…

Vite+Vue+iClient for Leaflet引入并实现MapV/Eharts第三方可视化库示例

作者&#xff1a;gaogy 文章目录 背景一、使用Vite构建Vue3JavaScript项目二、搭建iClient for Leaflet开发环境三、第三方可视化库Echarts的使用四、第三方可视化库MapV的使用五、其他地图库 背景 最近很多小伙伴咨询关于基于Vue3框架搭建iClent开发环境并使用Echarts与MapV等…

OPEN AI角色插件通道开放接入支持各种细分领域对话场景模型一键接入AI 智能

相信还是有很多伙伴不了解OPEN AI平台 &#xff0c;这里在细说一下 大家知道ChatGPT, 或者百度文心一言 阿里通意千问 包括各种其他的AI 聊天或者画图&#xff0c;等应用层出不穷。 但是我们要自己实现自己 语言大模型&#xff0c;或者说是人工智能应用能不能。 有实力当然可…

C++小项目之文本编辑器mynote(1.0.0版本)

2023年5月19日&#xff0c;周五晚上&#xff1a; 今天晚上突然想写一个运行在命令行上的文本编辑器&#xff0c;因为平时写文本时老是要创建新的文本文件&#xff0c;觉得太麻烦了。捣鼓了一个晚上&#xff0c;才选出一个我觉得比较满意的。我把这个程序添加到了系统环境变量中…

C语言指针学习笔记

1-二维数组指针 int a[3][4]a代表二维数组首元素的地址&#xff0c;此首元素不是一个简单的整形元素&#xff0c;而是由4个整形元素组成的一维数组&#xff0c;因此a代表的是首行&#xff08;序号为0的行&#xff09;的起始地址。a1代表序号为1的行的起始地址。a指向a[0], …

一个月50场面试,跑的慢就抢在别人前面!

300万字&#xff01;全网最全大数据学习面试社区等你来&#xff01; 今天的主人公也是一个应届生新人拿到满意offer的案例。 下面是一些聊天记录和面经&#xff0c;这名同学做的非常好的一个点&#xff0c;他把个人项目中的所用到的技术栈和项目具体的业务流程图以及用到的技术…

2年再见面

我和张哥是在两年前吃过饭&#xff0c;那时候我是在大学城上班。 两年前&#xff0c;张哥在微信上跟我说话&#xff0c;说要来深圳找我&#xff0c;问我什么时间方便&#xff0c;请我吃个便饭。两年前&#xff0c;公众号还比较火热。有挺多人找我做事情&#xff0c;找我做事情之…

桥梁安全监测,智能化桥梁结构健康监测方案

桥梁是现代城市交通网络中不可或缺的组成部分&#xff0c;但由于长期受到自然环境和人为因素的影响&#xff0c;桥梁的安全问题一直备受关注。传统的桥梁检测方式主要是靠人力进行巡查&#xff0c;这种方式效率低下、成本高&#xff0c;而且难以全面掌握桥梁结构的真实情况。随…

回顾 | Let's Learn .NET-通过 Semantic Kernel .NET SDK 管理你的 OpenAI 项目

点击蓝字 关注我们 编辑&#xff1a;Alan Wang 排版&#xff1a;Rani Sun Lets Learn .NET 系列 “Lets Learn .NET” 是面向全球的 .NET 初学者学习系列&#xff0c;旨在通过不同语言&#xff0c;帮助不同地区的开发者掌握最新的 .NET 开发知识与技能。 在 ChatGPT 与 OpenAI…

从零玩转设计模式之简单工厂设计模式-jiandangonchangmoshi

title: 从零玩转设计模式之简单工厂设计模式 date: 2022-12-08 11:31:19.472 updated: 2022-12-11 23:03:34.805 url: https://www.yby6.com/archives/jiandangonchangmoshi categories: - 设计模式 tags: - 设计模式 简单工厂模式是一种创建型设计模式&#xff0c;用于创建单…

Docker安装MinIO教程

本章教程&#xff0c;主要介绍一下&#xff0c;如何在Linux用Docker安装MinIO。 MinIO是一个高性能、分布式对象存储系统&#xff0c;支持S3 API&#xff0c;适用于云原生环境。MinIO可以在标准硬件上运行&#xff0c;并且具有低延迟、高吞吐量、高可用性和可扩展性等优势。Min…

C语言两百行代码实现简易扫雷

文章目录 前言一.代码实现二.设计思路main()函数搭建框架reset ( )函数dis_play( )函数setmine( )函数player_move( )函数 前言 扫雷应该是我们接触到的第一个电脑游戏&#xff0c;用c语言实现扫雷对初学者来说是一个不错的锻炼 编写扫雷只需要用到数组、函数和生成随机数的知…

Java文件与IO流

首先我们要清楚什么是流&#xff0c;正如其名&#xff0c;很形象&#xff0c;流就是像水一样的东西&#xff0c;具有方向性&#xff0c;在java中 &#xff0c;流大概就是类 接下来&#xff0c;我们要对输入输出流有一个基本认识&#xff0c;什么是输入输出流呢&#xff1f; 输入…

漏斗分析、 python学习路径地图、数据科学技能书知识地图、数据安全治理解决方案、AIGC发展研究、经营的本质…| 本周精华...

▲点击上方卡片关注我&#xff0c;回复“8”&#xff0c;加入数据分析领地&#xff0c;一起学习数据分析&#xff0c;持续更新数据分析学习路径相关资料~&#xff08;精彩数据观点、学习资料、数据课程分享、读书会、分享会等你一起来乘风破浪~&#xff09;回复“小飞象”&…

【计算机组成原理】(四)原码补码的加减乘除

各种码的作用&#xff1a; 模运算的性质&#xff1a; -3&#xff08;-1&#xff09;*129 90*129 211*129 332*129 -15&#xff08;-2&#xff09;*129 我们发现等号右边都是9&#xff0c;相当于等号的左边的数除去12的余数都是9 那我们就说这几个等好左边的数&#xff0…