使用Kotlin + JetPack 对旧项目进行MVVM改造

2023-11-10

介绍

本次改造的项目地址为:https://github.com/stevenwsg/XSYBBS

这个项目是两年前在学校写的,当初写的时候比较赶时间,一直堆业务功能,没有考虑项目结构,写了很多重复代码。最近在看Kotlin协程和JetPack组件,就想着用Kotlin协程和JetPack组件对原项目进行重构。

MVVM

Android MVVM 架构图:

bg2015020110.png

各层介绍:

  • Model层,主要负责数据的提供。Model层提供业务逻辑的数据结构(比如,实体类),提供数据的获取(比如,从本地数据库或者远程网络获取数据),提供数据的存储。
  • View层,主要负责界面的显示。View层不涉及任何的业务逻辑处理,它持有ViewModel层的引用,当需要进行业务逻辑处理时通知ViewModel层。
  • ViewModel层,主要负责业务逻辑的处理。ViewModel层不涉及任何的视图操作。ViewModel层中数据的变化可以自动通知View层进行更新,因此ViewModel层不需要持有View层的引用。

Google JetPack搭建MVVM:

mvvm.png

本次MVVM改造使用了JetPack的三个组件分别是:

  • Lifecycles
  • ViewModel
  • LiveData

Lifecycles

作用:更方便的处理Android中生命周期的问题,它可以使你的组件具有感知生命周期的能力,从而根据生命周期状态来自动的响应一些动作。

使用文档:https://developer.android.com/topic/libraries/architecture/lifecycle

ViewModel

作用: 用来管理数据,它同样具有感知生命周期的能力,在宿主没有被销毁之前,数据不会丢失,且ViewModel不会重新创建,比如旋转屏幕等。同时,ViewMedel将数据从Activity中抽离出去,耦合度更低,更加方便维护。

使用文档:https://developer.android.com/topic/libraries/architecture/viewmodel

LiveData

配合ViewModel一起使用,存在于ViewModel中

LiveData 是一个可观测数据的容器类,与普通的可观测类不同,LiveData 能感知生命周期,并且只会在这些可观测的应用组件处于活动状态的时候才会更新它们,而且还会在与其关联的生命周期被销毁后自动清理自己。这样一来也就不会出现内存泄漏的问题了。

作用:底层数据改变时会自动更新UI,实际上我们可以看做是ViewModel于View之间通信的桥梁

使用文档:https://developer.android.com/topic/libraries/architecture/livedata

改造用户反馈模块

在项目中添加 lifecycle-extensionsKotlin 依赖

    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation "androidx.core:core-ktx:1.2.0"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

下面是项目的结构:

项目结构

  • bean 反馈实体和请求返回实体
  • model 存放业务逻辑相关
  • view 存放Activity
  • viewmodel 存放viewmodel相关类

在MVVM中,通过LiveData来实现ViewModel与View层之间的通信的,而且这个通信不是手动的,其核心是通过数据驱动的,也就是数据发生变化,view层会感知到并自动刷新ui。

1、View

View 持有ViewModel 的引用,当需要和Model进行通信时,通过ViewModel来进行通信。同时监听ViewModel中的数据变化,当ViewModel中的数据改变时,刷新UI,实现数据驱动。

class FeedBackActivity : BaseActivity() {

    private var mFeedBackVM : FeedBackViewModel? = null // 持有ViewModel的引用

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_feedback)
        initView()
        initVM()
        initObserval()
    }

    private fun initView() {
        bt_back.setOnClickListener {
            if (!TextUtils.isEmpty(et_back.text.toString())) {
                mFeedBackVM?.getFeedBackMessage(et_back.text.toString()) // 调用ViewModel 的反馈方法, 解耦,单一职责
            } else {
                Toasty.info(this@FeedBackActivity,  getString(R.string.text_tost_empty), Toast.LENGTH_SHORT, true).show()
            }

        }
    }

    private fun initVM() { // 初始化ViewModel
		mFeedBackVM = ViewModelProvider(this).get(FeedBackViewModel::class.java)
    }

    private fun initObserval() { // 观测数据,当ViewModel的LiveData数据改变时,更新UI
        mFeedBackVM?.messageLiveData?.observe(this, Observer { t ->
            if (t?.code == 0) {
                Toasty.success(this@FeedBackActivity, t.message, Toast.LENGTH_SHORT, true).show()
                finish()
            } else {
                t?.message?.let { Toasty.error(this@FeedBackActivity, it, Toast.LENGTH_SHORT, true).show() }
            }
        })
    }
}
2、ViewModel

ViewModel 使用ViewModelScope协程来发起网络请求,将结果使用LiveData 发送到上层。

class FeedBackViewModel : ViewModel() {

    var messageLiveData = MutableLiveData<FeedBackResultMessage>()
    private var feedBackResultMessage: FeedBackResultMessage? = null

    fun getFeedBackMessage(content: String) {
        viewModelScope.launch(Dispatchers.IO) {
            val feedBack = Feedback(content)
            feedBack.save(object : SaveListener<String>() {
                override fun done(p0: String?, p1: BmobException?) {
                    feedBackResultMessage = if (p1 == null) {
                        FeedBackResultMessage(
                            FeedBackResultMessage.CODE_SUCCESS,
                            FeedBackResultMessage.MESSAGE_SUCCESS
                        )
                    } else {
                        FeedBackResultMessage(
                            FeedBackResultMessage.CODE_ERROR,
                            FeedBackResultMessage.MESSAGE_ERROR
                        )
                    }
                    messageLiveData.postValue(feedBackResultMessage)
                }
            })
        }
    }
}
3、Bean

反馈实体

data class Feedback (var Content : String,
                    var deviceType : String = "android",
                    var userid : String = BmobUser.getCurrentUser(User::class.java).objectId) : BmobObject() //以前项目中使用了Bmob的数据库存储服务

反馈结果实体

/*
 * code 0 代表成功
 * code 1 代表失败
 */
data class FeedBackResultMessage (val code : Int, val message: String) {

    companion object {
        const val CODE_SUCCESS : Int = 0
        const val CODE_ERROR : Int = 1

        const val MESSAGE_SUCCESS : String = "反馈成功~~~"
        const val MESSAGE_ERROR : String = "反馈失败~~~,请检查网络"
    }
}

总结

MVVM优点:

  • 降低耦合度
  • 数据驱动
  • 可以异步线程更新数据
  • 易于单元测试
  • 方便协同开发等

目前已经使用这种改造方法改造了反馈模块,修改密码模块,发帖模块。后续的话逐渐把整个项目使用MMVM进行改造。

感兴趣的同学可以看看:https://github.com/stevenwsg/XSYBBS

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用Kotlin + JetPack 对旧项目进行MVVM改造 的相关文章

  • 使用街景图像

    我想获取街景图片 注明纬度和经度 并显示在对话框中 这可能吗 我在这里看到了一些示例 但没有找到一个向我展示如何在对话框中显示图像的示例 抱歉 如果网站中已经存在这个问题 但我在搜索时没有找到 是的你可以 作为 URL 根 你可以使用这个h
  • Android 的 Firestore 超时

    我目前正在构建一个应用程序 将用户的博客文章保存在Firestore服务器 一切正常 但我发现该帖子在不稳定的互联网连接下无法上传 我尝试设置一个超时到Firestore实例 但 Firestore 库似乎没有超时选项 问题是 由于没有超时
  • 使用JACK时生成的proguard mappings.txt文件在哪里?

    我一直在尝试使用最新的JACK 和 JILL 构建系统到我的android项目 我知道JACK进程包括proguard处理 但之后我找不到映射 txt归档回溯堆栈跟踪Google Play 开发者控制台上提供的错误数 请帮我查找映射 txt
  • Android 中的振动器

    如何创建Vibrator对象并调用vibrate函数 http developer android com reference android os Vibrator html http developer android com refe
  • 如何立即开始执行 Kotlin 协程

    我想立即启动一个协程 我有一段代码 class SampleActivity AppCompatActivity CoroutineScope private var job Job Job override val coroutineCo
  • 如何获取firebase数据库中所有孩子的数据?

    我有这个 firebase 数据库 我需要获取用户的所有电话号码 我应该使用哪个侦听器来获取所有孩子 每个用户都作为一个对象添加 其中用户 ID 作为该对象的名称 我需要在不知道用户 ID 的情况下检索该对象 我搜索了文档 它与DataSn
  • android 无法解析方法 setcontentview

    今天在android studio 中遇到了一个错误 我正在尝试在应用程序中创建一个关于我们的屏幕 布局 xml 文件已创建 任何帮助表示赞赏 谢谢 错误 无法解析方法 setcontentview int package example
  • 在原生 Android 应用程序中集成多个 Unity 游戏

    我有一个原生 Android 应用程序 我想在其中嵌入多个 Unity 游戏 我跟着link https medium com davidbeloosesky embedded unity within android app 7061f4
  • 无法将库添加到我的 Android 项目

    我正在创建一个新应用程序 我想使用一些像这样的库 https github com JakeWharton Android ViewPagerIndicator https github com JakeWharton Android Vi
  • 查找 ImageView 相对于其显示的图像的位置

    所以问题就在这里 我在 ImageView 中显示一个大图像 需要找到它相对于图像的位置 像这样 Image gt ImageView
  • SpannableString 中的 URLSpan

    我正在使用这个例子SpannableString http developer android com resources samples ApiDemos src com example android apis text Link ht
  • Android Studio安装JDK错误

    In Android Studio I am facing bellow error 当我按下时会显示此弹出窗口Alt Enter对于缺少的类 符号 当我点击 setup SDK 时 它显示两个选项 1 8 Java版本 1 8 0 60
  • 如何在两种不同模式、两种布局中设置方向?

    我有一个叫做Main XML我将方向设置为纵向AndroidManifest xml 我也为 Honeycomb 设计了这个布局并将其放置在layout xlarge mdpi文件夹 但我想使用Main XML in layout xlar
  • Android BottomNavigationView 与自定义视图作为图标[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在尝试 Android 支持库中的新 BottomNavigationView 对于其中一个菜单项 我希望有一个自定义视图 以便我
  • 找不到满足版本限制的“com.google.code.findbugs:jsr305”版本

    当生成签名的 APK 进行发布时 我收到此错误消息 Cannot find a version of com google code findbugs jsr305 that satisfies the version constraint
  • 在 Android(JB 上)中,如何向自定义丰富通知添加操作?

    我一直在使用 Jelly Bean 中新的丰富通知 当我使用模板设置新通知时 一切都按预期工作Notification BigPictureStyle Notification BigTextStyle or Notification In
  • 如何为Android设置图像顶部和底部相同的大小?

    我想在中心 顶部和底部显示相同尺寸的图像 请参阅下面的屏幕 有人知道请给我代码 谢谢大家 Use android scaleType centerInside or ImageView setScaleType ImageView Scal
  • Android 通知上有按钮

    我正在尝试使用 2 个按钮发出通知 一个带我回到活动 另一个将其关闭 有谁知道如何捕获按钮单击事件 请记住活动已暂停 我很高兴发布它 经过一夜的工作 我发现了一些东西 那么 我们开始吧 1 为您的通知创建 xml 布局文件 2 使用Noti
  • 如何在android中使用Room Persistence ORM工具实现created_at和updated_at列

    我该如何实施created at and updated at在Android中使用Room Persistence ORM工具的列 可以在创建或更新表中的行时自动更新时间戳 我研究了很多网站 但仍然没有找到任何可以处理的结果middlew
  • 在活动之间共享菜单栏

    我的应用程序上有一个菜单栏 我需要在 5 个活动之间共享该菜单栏 我的菜单栏 5 个允许在活动之间切换的按钮 对于任何活动具有完全相同的 UI 和相同的行为 因此我想共享菜单栏 XML 视图代码和控制器代码 我已经找到了一种使用共享 XML

随机推荐

  • linux部署tomcat项目详细教程(安装linux到部署tomcat)

    近来想要研究下linux 所以就搭了个linux系统来配置服务器玩玩 这里分了个目录 如果已经安装好虚拟机或者linux系统的小伙伴可以直接跳过前面的安装介绍 直接看部署 文章目录 一 总步骤说明 二 安装虚拟机 三 创建linux系统 四
  • DQL基础查询

    一 基础查询 1 语法 select 查询列表 from 表名 select后面跟的查询列表 可以有多个部分组成 中间用逗号隔开 例如 select 字段1 字段2 表达式 from 表 2 特点 查询的结果集是一个虚拟表 3 执行顺序 f
  • 循环神经网络RNN论文解读

    版权声明 本文为CSDN博主 了不起的赵队 的原创文章 遵循CC 4 0 by sa版权协议 转载请附上原文出处链接及本声明 原文链接 https blog csdn net zhaojc1995 article details 80572
  • Linux网络和安全:配置、远程访问与防御指南

    文章目录 Linux 网络和安全 引言 网络配置 IP地址配置 配置网络接口 防火墙设置 安全性加强 Linux网络配置及端口管理 网络配置命令 端口管理 防火墙和安全性设置 防火墙管理工具 安全性设置 Linux远程访问技术 SSH和VP
  • leetcode Path Sum

    Definition for a binary tree node struct TreeNode int val TreeNode left TreeNode right TreeNode int x val x left NULL ri
  • 基于B/S的网上零食销售系统的设计与实现(附:源码 论文 Sql文件)

    摘要 本文介绍了网上零食销售系统的整个开发过程 采用国内认准的B2C商城建站系统模式 并按照现有的购物系统的现状而设计开发的网络买卖平台 本文主要阐述的了整个系统的完成过程 模拟了一个具备卖家 买家和管理员的网络交易系统 而本平台对不同的用
  • 若依打包上线前后端配置

    1 后台访问打包设置 vue config js 文件中需要修改代理地址 devServer host 0 0 0 0 host 188 188 188 64 port port open true proxy detail https c
  • STM32进入STOP模式并唤醒实验总结

    项目需求 需要实现设备低功耗功能 实现过程中遇到几个问题 以此记录总结 stm32f103ret6 问题一 执行PWR EnterSTOPMode PWR Regulator LowPower PWR STOPEntry WFI 后 程序继
  • 进程间通信:比较脸熟的ftok()

    老师在讲这个函数时没有什么感觉 当我做了试验后 其实也没有什么感觉 就是当我在改进实验的时候 问题就来了 就在ftok 这出的的错误 不过先不去了解它的作用来先说说为什么要用它 共享内存 消息队列 信号量它们三个都是找一个中间介质 来进行通
  • OpenSSL:调用OpenSSL实现SHA算法

    安装 libssl dev sudo apt get install libssl dev example c include
  • 用python实现打字练习网站第一

    一 简介 在在线打字测试 dazi kukuw com 网站中 本人kpm一直不高 想着是否能用python写个脚本来改善下 于是选择用python的Selenium来实现 也对其中遇到一些常见问题进行解决 二 正文 1 首先 webdri
  • Notepad++安装NppFTP的和NppFTP的使用

    1 NotPad 插件的安装 NotPad 提供了很多方便的插件以供我们使用 没有的插件需要我们自己安装 安装分为手动安装和自动安装 1 gt 自动安装 选择需要的插件安装即可 安装完成就可以看见所安装的插件 如果在线不能安装就需要手动安装
  • python进阶篇

    想必看到这篇文章的朋友都已经有了一定的基础 已经能够理解python的语法 库的使用 循环遍历以及抛出异常 此时的我们已经拥有了解决问题的能力 但可能自己写不出代码 就像我们学数学 前面的低中档题可能不在话下 所向披靡 但一遇到压轴题就歇菜
  • ER模型详解-陈氏模型

    转载自 http blog 163 com magicc love blog static 18585366220142125836878 Entity Relationship Model ER模型 实体关系模型 1976年Peter C
  • thinkphp 生成runtime.php,彻底关闭ThinkPHP日志功能 关闭Runtime中的日志方法

    彻底关闭ThinkPHP日志功能 从ThinkPHP的核心文件里寻找入口 直接贴上代码 该配置文件位置为 ThinkPHP Conf debug php 保存 好了 2 将LOG LEVEL允许记录的日志级别设置为空 则不会记录日志 3 关
  • zabbix详解(二)—— zabbix故障自愈

    今天继续给大家介绍Linux运维相关知识 本文主要内容是zabbix的故障自愈 在上文zabbix的使用中 我们自定义了一个可以监控85端口jar服务的监控项 今天 我们就尝试正式使用该监控项 并定义相对应的触发器 最终实现邮件报警功能 及
  • Microsoft NNI入门

    GiantPandaCV导语 Neural Network Intelligence 是一个工具包 可以有效帮助用户设计并调优汲取学习模型的神经网络架构 以及超参数 具有易于使用 可扩展 灵活 高效的特点 本文主要讲NNI基础的概念以及一个
  • C++创建对象时报错:引发了异常: 读取访问权限冲突。 p2.m_Height 是 nullptr。

    未修改前的类代码如上 Person5类在test09 函数中创建p1对象 报错信息如下 报错信息指向第38行代码 解决方法 将Person5类中的拷贝构造函数注释掉即可编译通过 引发了异常 读取访问权限冲突 p2 m Height 是 nu
  • 简单说说多益笔试

    一 选择题 考了spring java虚拟机 二 填空题 忘了 三 简答题 1 面向对象三个特性 2 三次握手 四次握手 3 数据库操作 四 编程题 1 数学题 知道首项 前项与后项的差 2 偶数二进制数反转 3 一堆数中找出等于s的个数
  • 使用Kotlin + JetPack 对旧项目进行MVVM改造

    介绍 本次改造的项目地址为 https github com stevenwsg XSYBBS 这个项目是两年前在学校写的 当初写的时候比较赶时间 一直堆业务功能 没有考虑项目结构 写了很多重复代码 最近在看Kotlin协程和JetPack