kotlin——MVVM框架下的大型项目优化、以及activity和viewmodel臃肿的优化

目录

概要

优化思路

一、重构过长的Activity

二、优化臃肿的ViewModel

示例代码:

1.Activity封装到单独的Fragment中

2.把ViewModel拆分成多个子viewmodel

小结


概要

在大型项目中,随着项目越做越大,activity和viewmodel的代码会越来越多,尽量保持Activity和ViewModel的代码精简和易于维护是非常重要的。个人建议700行以上就应该考虑,尽量让代码控制在1000行以内。

不然随着代码多维护起来困难,代码混乱,有bug时定位问题难,增加需求代码难等问题就会随之而来,那应该怎么办呢?

优化思路

一、重构过长的Activity

  1. 功能拆分:如果Activity承载了多个不同功能区域的UI,可以考虑将每个区域封装到单独的Fragment或子Activity中。这样可以将每个功能区域的逻辑和UI代码分开,使Activity更加简洁。
  2. 提取组件:将重复的UI元素或逻辑封装成自定义View或辅助类,减少Activity的体积。
  3. 职责分离:确保Activity只处理与UI生命周期相关的事件和逻辑。将业务逻辑和数据处理移至ViewModel
  4. 接口封装:设计接口来隔离Activity与其他层(如数据层)的直接交互,降低耦合度。
  5. 提取工具类和辅助类:如果Activity中有一些公共的、可重用的代码片段,可以将其提取到单独的工具类或辅助类中,并在Activity中通过调用这些方法来实现功能。

二、优化臃肿的ViewModel

  1. 数据抽象:将数据处理逻辑放到专门的Model层或Repository层,ViewModel仅负责协调和触发数据更新。
  2. 状态管理:使用StateFlow或其他状态管理库来简化状态的持有和更新,避免手动管理大量状态变量。
  3. 多用LiveData:利用LiveData的观察者模式自动管理数据的生命周期,减少在ViewModel中的生命周期处理代码。
  4. 逻辑外包:将业务处理逻辑外包给专门的用例类(Use Case Classes)或领域服务(Domain Services)。
  5. 作用域限定:限定ViewModel的作用范围,例如使用Navigation的Scoped ViewModel,确保ViewModel只在需要的屏幕中使用。
  6. 数据拆分:如果ViewModel中处理的数据过多,可以考虑将其拆分为多个小的ViewModel,每个ViewModel只处理一部分数据。这样可以使每个ViewModel更加专注和易于理解。

示例代码:

1.Activity封装到单独的Fragment中
// FirstFragment .kt
class FirstFragment : Fragment() {override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_a, container, false)}
}// SecondFragment .kt
class SecondFragment : Fragment() {override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_b, container, false)}
}
class MainActivity : AppCompatActivity() {private lateinit var fragmentManager: FragmentManageroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)fragmentManager = supportFragmentManager// 添加第一个区域addFragment(FirstFragment())// 添加第二个区域addFragment(SecondFragment())}private fun addFragment(fragment: Fragment) {val transaction: FragmentTransaction = fragmentManager.beginTransaction()transaction.add(R.id.fragment_container, fragment)transaction.commit()}
}
2.把ViewModel拆分成多个子viewmodel

假设我们有一个应用,它有两个页面:用户列表页面和用户详情页面。我们可以将这两个页面的业务逻辑分别放在两个ViewModel中。

首先,创建一个UserListViewModel,用于处理用户列表页面的逻辑:

class UserListViewModel : ViewModel() {private val _users = MutableLiveData<List<User>>()val users: LiveData<List<User>> = _usersfun fetchUsers() {// 模拟从网络或数据库获取用户列表val userList = listOf(User("张三", 25),User("李四", 30),User("王五", 35))_users.value = userList}
}

然后,创建一个UserDetailViewModel,用于处理用户详情页面的逻辑:

class UserDetailViewModel : ViewModel() {private val _user = MutableLiveData<User>()val user: LiveData<User> = _userfun setUser(user: User) {_user.value = user}
}

最后,在Activity或Fragment中,将这两个ViewModel关联起来:

class UserListActivity : AppCompatActivity() {private lateinit var userListViewModel: UserListViewModelprivate lateinit var userDetailViewModel: UserDetailViewModeloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_user_list)userListViewModel = ViewModelProvider(this).get(UserListViewModel::class.java)userDetailViewModel = ViewModelProvider(this).get(UserDetailViewModel::class.java)userListViewModel.users.observe(this, Observer { users ->// 更新用户列表UI})// 当点击用户时,设置用户详情ViewModel的数据并跳转到用户详情页面userListView.setOnItemClickListener { parent, view, position, id ->val selectedUser = users[position]userDetailViewModel.setUser(selectedUser)startActivity(Intent(this, UserDetailActivity::class.java))}}
}

这样,我们就将原本一个大的ViewModel拆分成了两个小的ViewModel,分别处理用户列表页面和用户详情页面的业务逻辑。

小结

  1. 拆分功能:将大型类拆分为多个小类,每个类负责一个特定的功能或职责。
  2. 代码审查(Code Review):定期进行团队内部代码审查,发现并修复代码中的冗余和不良编码习惯。

  3. 使用扩展函数:将activity或者ViewModel的一些逻辑封装为扩展函数。
  4. 使用辅助类:创建辅助类来处理activity或者ViewModel中的某些逻辑。
  5. 使用委托:使用Kotlin的by关键字委托给其他对象。(可以看另一篇关于委托的介绍:kotlin——委托(使用委托类来实现多继承)、使用委托类来创建viewmodel实例、内部类实现多继承、使用委托把activity的部分职责代码分离出来_kotlin 多继承-CSDN博客)

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

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

相关文章

【Unity小技巧】记一个RenderTexture无法正确输出Camera视图下的Depth渲染的问题

问题 这个问题出现在使用URP管线时&#xff0c;我试图用Shader实现血条的制作&#xff0c;并用RenderTexture将视图渲染到RawImage上。 但是渲染结果出现了问题&#xff1a; 可以看到液体边缘的渲染出现了错误&#xff0c;原因不明 在StackFlow上查找后找到了类似的问题&…

Spring Cloud - 开发环境搭建

1、JDK环境安装 1、下载jdk17&#xff1a;下载地址&#xff0c;在下图中红色框部分进行下载 2、双击安装&#xff0c;基本都是下一步直到完成。 3、设置系统环境变量&#xff1a;参考 4、设置JAVA_HOME环境变量 5、在PATH中添加%JAVA_HOME%/bin 6、在命令行中执行&#xff1a;j…

第三十篇——等价性:如何从等价信息里找答案?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 知道了等价性的逻辑&#xff0c;通过等价性去衡量事物&#xff0c;像是给…

QPaintEngine

当使用 Qt 进行绘图操作时&#xff0c;QPaintEngine 的方法在底层起着重要作用。以下是一个更详细的示例&#xff0c;展示了如何在自定义的 QWidget 子类中使用 QPaintEngine 的方法进行绘图操作&#xff1a; #include <QWidget> #include <QPaintEvent> #include…

1.1、Redis系列-Epoll 的高效工作流程

epoll 的高效工作流程 epoll 是 Linux 操作系统提供的一种高效 I/O 多路复用机制。它的设计初衷就是为了高效地处理大量并发连接&#xff0c;解决 select 和 poll 的性能瓶颈问题。下面详细解释 epoll 的高效工作流程&#xff0c;并重点突出其高效性。 一、创建 epoll 实例 …

Linux配置网卡详细教程

这个网卡配置然后头痛了两天&#xff0c;看了很多篇关于这方面的文章&#xff0c;但是都没让我成功&#xff0c;可惜工亏不负有心人&#xff0c;然后终于学会了下面此方法 实现完成的效果&#xff1a; 永久修改网卡IP vi /etc/sysconfig/network-scripts/ifcfg-ens33 TYPEEther…

node带参数命令

不带参数命令示例&#xff1a; node /www/wwwroot/server 带参数命令示例&#xff1a; node /www/wwwroot/server arg1 arg2 arg3 在启动页进行参数处理&#xff1a; // 获取启动参数(除去前2个默认参数&#xff0c;示例&#xff1a;node /www/wwwroot/server arg1 arg2 …

西门子840dsl机床仿真软件配置opcua说明

需要的安装包如下&#xff0c;可在百度网盘中下载 主软件包&#xff1a;sinutrain-v4.7-ed4&#xff08;也可在官网中下载最新版本&#xff09; 用户文件&#xff1a;UserDataBase 授权sinutrain&#xff1a;Sim_EKB_Install_2021_06_22 链接&#xff1a;https://pan.baidu.c…

小阿轩yx-用户管理与高级SQL语句

小阿轩yx-用户管理与高级SQL语句 MySQL 进阶查询 运维工作中可以提供不小的帮助&#xff0c;运维身兼数职&#xff0c;可能会有不少数据库的相关工作 常用查询介绍 对查询的结果集进行处理 按关键字排序 使用 SELECT 语句可以将需要的数据从 MySQL 数据库中查询出来 对结…

1.0.计算机系统知识

考点分布&#xff1a;3 ~ 7分&#xff0c;历史平均5分&#xff0c;选择题 CPU 运算器和控制器的组件及它们的功能和特点。 数据的表示 定点数 原码、反码、补码、移码的计算 浮点数 阶码表示范围 尾数表示精度 校验码 奇偶校验、CRC循环冗余校验、海明校验。 其中 CRC循…

第一百二十六节 Java面向对象设计 - Java枚举类

Java面向对象设计 - Java枚举类 枚举类型的超类 编译枚举类型时&#xff0c;编译器会创建一个类。 枚举类型可以具有构造函数&#xff0c;字段和方法。枚举类型仅在编译器生成的代码中实例化。 每个枚举类型都隐式地扩展java.lang.Enum类。 Enum类中定义的所有方法都可以与…

PostgreSQL 索引优化与性能调优(十一)

1. 索引基础知识 1.1 什么是索引 索引是一种数据结构&#xff0c;用于快速定位和访问数据库表中的特定行。在 PostgreSQL 中&#xff0c;常见的索引类型包括 B-tree、哈希、GiST 和 GIN 等。 1.2 创建索引 1.2.1 创建 B-tree 索引 CREATE INDEX idx_column ON table_name …

从一到无穷大 #29 ByteGraph的计算,内存,存储三级分离方案是否可以通用化为多模数据库

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言ByteGraph现有架构阿里云Lindorm腾讯YottaDB多模型化修改点ByteGraph论文中的优化…

PD虚拟机支持M3吗 PD虚拟机怎样配置图形卡

最近有很多人在问M3芯片的苹果电脑和M2相比&#xff0c;有哪些提升的功能。实际上&#xff0c;M3芯片的苹果电脑拥有与M2相同的CPU与GPU数量&#xff0c;但比M2多50亿个晶体管&#xff0c;并引入了动态缓存、增强型神经网络引擎等技术&#xff0c;性能、功能均进一步加强。面对…

Ubuntu22 更新内核后终端输入卡顿,最简单的解决方案

在系统升级后相信很多人都遇到了这个问题&#xff0c;系统终端输入卡顿&#xff0c;但是ssh远程进来不卡&#xff0c;使用第三方终端也不卡,…&#xff0c;今天终于忍不了&#xff0c;解决了 现象&#xff1a; 更新Nvidia驱动后,内核进行了自动编译升级。 之后的一段时间使用…

从零开始做题:修猫

修猫 1 题目 2 解题 2.1 使用Stegslove分析图片 (base) ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc] └─$ java -jar Stegsolve.jar 2.2 analyse -frame browser 2.3 得到flag DASCTF{818ca3a840e768da7d5fcdeaedd5012f}

IDEA随时随地破JIE

IDEA下载网站&#xff1a;https://www.jetbrains.com/idea/download/other.html 破解网站&#xff1a; https://3.jetbra.in/ 破解方法&#xff1a; 进入下方网站&#xff1a; JETBRA.IN CHECKER | IPFS 选择图中所示选项 下载zip文件到电脑上&#xff08;这个网站先别关…

ROS2中的CMakeLists(一)——基础知识

在使用ROS2框架开发机器人应用时&#xff0c;对各个功能包Cmakelist.txt文件的更改尤为重要。本系列旨在总头开始介绍Cmakelist.txt各条语句的意义和内涵。 Cmake已经是高度集成的构建工具&#xff0c;其作用是在不同开发环境下生成makefile文件&#xff0c;以此来执行make指令…

【分布式文件系统HDFS】API 编程基础

目录 一、使用 HDFS API 完成以下程序设计并运行 1. 将 HDFS 文件系统目录/user/账户名下的文件 test1.txt 下载至本地文件系统目录/home/账户名/Desktop 下。 1.1 程序代码 1.2 运行截图 1.3 查看本地的test1.txt文件 2. 在 HDFS 文件系统上创建目录/test1 2.1 程序代码…

nginx 403报错分析

问题出现&#xff1a; 中心灾备数据同步&#xff0c;进行切换演练前准备&#xff0c;两边配置一致&#xff0c;但是灾备随意挑选nginx目录文件进行查看&#xff0c;发现报错403错误 分析&#xff1a; &#xff08;1&#xff09;查看日志&#xff1a;于是查看nginx日志&#xff…