内容简介:公司的项目一直是以 Activity 为载体的 Android 式 MVC 架构,上手快,大多数页面代码也挺容易读的。只是某复杂业务的 Activity 会有上千行的代码,内部复杂的状态判断和异步逻辑特别多,而且原作者早已离职,每次提测都只能祈求这里不出 bug。为了重构这里的代码,引入 MVP 或 MVVM 是比较合适的方案。精简原有的逻辑也可以一定程度上增加代码的可读性,但还是难以避免单个 Activity 中存在大量代码的问题。MVP 似乎是 Android 开发中更加流行的方案(样本数为2,两个同
公司的项目一直是以 Activity 为载体的 Android 式 MVC 架构,上手快,大多数页面代码也挺容易读的。只是某复杂业务的 Activity 会有上千行的代码,内部复杂的状态判断和异步逻辑特别多,而且原作者早已离职,每次提测都只能祈求这里不出 bug。
为了重构这里的代码,引入 MVP 或 MVVM 是比较合适的方案。精简原有的逻辑也可以一定程度上增加代码的可读性,但还是难以避免单个 Activity 中存在大量代码的问题。MVP 似乎是 Android 开发中更加流行的方案(样本数为2,两个同事都用过),但 MVP 的问题也是可预见的。恰好 Google 在 Jetpack 的 Architecture 中又宣传了一波 MVVM,跟大佬们商量之后,我决定先改写一个 Activity 试试。
MVC/MVP/MVVM 的介绍就省略了,下面简单说明一下用到的技术。
知识准备:数据绑定方法
数据绑定到 View 是 MVVM 的核心,对于不同的应用场景需要使用不同的数据绑定手段:
- databinding 是常被提及的数据绑定框架,应用于将数据直接绑定到 layout 文件,可以有效的给 Activity 减负。
- LiveData 是另一种 Google 推荐的方案,当 LiveData 作为数据源,既可以结合 databinding 将数据变化更新到 layout 中,也可以在 Activity 中设置 Observe 回调,实现更多 layout 中做不到的 View 效果(比如显示一个 dialog)。
二者都是 Google 出品,具体如何使用就不赘述了,后面会单独把遇到的坑记录下来。
实践过程简述
先简单说一下功能吧,改动之前的代码就不贴了,毕竟是公司的项目。
核心流程大概是这样的,还有一些暂停、模式切换和 postDelay 制造的延迟效果,整个流程中充满了各种异步操作,每个异步操作的回调中都需要判断一连串的状态,比如页面是否在显示中,音频是否正在播放等。
为了改写成 MVVM 模式的代码,首先要区分开哪些属于 View 层,哪些属于 ViewModel 层。只声明主要流程的话,内容有以下几点:
功能点 | View 层 | ViewModel 层 |
---|---|---|
倒计时321 | 显示倒计时的 Dialog | 每秒更新剩余时间(321) |
播音频 | 显示播放进度条(%) | 控制播放及回调处理 |
录音 | 显示录音进度条(时长等于原音频,并非手动停止) | 控制录音及回调处理,录音计时停止 |
提交数据 | 提交中显示 loading | 发起网络请求提交数据 |
暂停 | 显示暂停 Dialog,恢复其他 View | 停止当前操作,回到当前题目最初状态 |
稍微分析一下,除了 Dialog 之外的 View 改动尽量使用 databinding 直接放在 layout 中,Dialog 的显示和隐藏都由一个 Boolean 类型的 LiveData 来控制,Activity 中基本只需要写 ViewModel/databinding 的初始化代码和 Dialog 相关代码。
ViewModel 中是全部的业务逻辑代码,但不持有任何 View 相关的实例,所有的改变都作用于数据即可。另外,由于 databinding 和 LiveData 都是对生命周期友好的框架,在 View 层销毁后更新数据并不会导致崩溃,在充满异步操作的逻辑中可以节省很多个 if 判断。
中途发现这个 RecyclerView 的交互太复杂了,databinding 中需要大量的 if 判断,为了加强代码的可读性,就把 adapter 相关的绑定采取 LiveData 实现了。最终 ViewModel 只有以下几个可观察数据:
简单画了一下重写前后的主流程图
提交后跳转页面的 Intent 需要传递多个数据,这里用了一个 Bundle 类型的 LiveData,在 Activity 中直接使用 Intent.putExtras 把值放进去即可。同理,在 ViewModel 中初始化数据时也可以把 getIntent().getExtras() 传过去。
踩坑记录
1. Kotlin 与 databinding 的兼容性问题以及不同 Android Studio 版本的区别。
在 Android Studio 3.2 之前,databinding 需要添加一个 kapt 的 databinding-compiler 依赖,具体的版本号也需要对应,否则编译后无法生成 Binding 类,就会出现 cannot resolve symbol xxxxBinding 的错误。
在 Android Studio 3.2 之后正好相反,如果不删除这个依赖就会报错。
具体描述可以看这个: stackoverflow.com/questions/5…
2. databinding 和 recyclerview 怎么合作。
直接和数据打交道的 View 很容易转换成使用 databinding 的代码,但 RecyclerView 这种需要一个 adapter 的 View 就会面临许多麻烦。github 上有些针对列表类 View 使用 databinding 的框架, 甚至可以做到不用再写 adapter,大多数场景下是可以用的,唯一的缺点是 debug 艰难。
但是我没选择这种方案,当 RecyclerView 中存在复杂的交互逻辑时,使用 databinding 会产生特别多的状态数据,反而让代码更加复杂了。不改变 adapter 的写法,可以用 LiveData 在 Activity 中把值传到 adapter 中。
3. 只进行一次触发的 View 操作如何处理。
大多数 Data 都表示一个状态,比如 Dialog 是否展示,TextView 的文本内容等。但有些特殊的 View 层变化只需要一个触发,比如 Toast 和 SnackBar。
从原则上看,ViewModel 显然不应该处理 Toast,但 Toast 这种非常轻量又可以用 ApplicationContext 来实现的,稍微违背一下规则我个人也能接受……
当然,不能推荐大家也都这么搞,google sample 的 architecture 项目中有一个SingleLiveEvent,可以直接复制出来用。项目地址: github.com/googlesampl…
完成后的一些个人理解
什么时候需要 MVVM?
什么时候都可以用。虽然对于简单的业务逻辑来说代码量会增加, 但是 MVVM 的思考方式会让代码更容易维护 。过去代码都写在 Activity 中时,方法的拆解通常只考虑功能的相关程度和代码行数,不会刻意区分 View 和逻辑。后期经过不同的人修改 bug,就会越来越混乱。
以上所述就是小编给大家介绍的《记一次 MVVM 实践》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- vue项目实践004~~~一篮子的实践技巧
- HBase实践 | 阿里云HBase数据安全实践
- Spark 实践:物化视图在 SparkSQL 中的实践
- Spark实践|物化视图在 SparkSQL 中的实践
- HBase实践 | 数据人看Feed流-架构实践
- Kafka从上手到实践-实践真知:搭建Zookeeper集群
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
统计自然语言处理基础
Chris Manning、Hinrich Schütze / 苑春法、李伟、李庆中 / 电子工业出版社 / 2005-1 / 55.00元
《统计自然语言处理基础:国外计算机科学教材系列》是一本全面系统地介绍统计自然语言处理技术的专著,被国内外许多所著名大学选为计算语言学相关课程的教材。《统计自然语言处理基础:国外计算机科学教材系列》涵盖的内容十分广泛,分为四个部分,共16章,包括了构建自然语言处理软件工具将用到的几乎所有理论和算法。全书的论述过程由浅入深,从数学基础到精确的理论算法,从简单的词法分析到复杂的语法分析,适合不同水平的读......一起来看看 《统计自然语言处理基础》 这本书的介绍吧!