尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
展示学习笔记
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
再然后用了两篇讲述了 MVVM 架构是如何解决 MVP 的痛点:
- ViewModel 的引入使得“有免死金牌的业务层”成为可能,也使得跨界面之间的业务逻辑共享以及通信变得轻松。
- LiveData 的引入使得业务层成为数据持有者以数据驱动刷新界面,还避免了生命周期问题以及内存泄漏风险。
- 因为数据持有者,MVVM 也引入了新的复杂度,首先是不好处理的粘性数据问题,更棘手是更新数据的方法是带有副作用的,由此会引发界面状态不一致问题。
关于 MVVM 架构的详细分析可以点击下面的链接:
从这一篇开始,试着引入 MVI 架构的思想进行搜索业务场景的重构,看看是否能解决上述痛点。
在重构之前,再介绍下搜索的业务场景,业务流程如下:在搜索条中输入关键词并同步展示联想词,点联想词跳转搜索结果页,若无匹配结果则展示推荐流,返回时搜索历史以标签形式横向铺开。点击历史可直接发起搜索跳转到结果页。
将搜索业务场景的界面做了如下设计:
搜索页用Activity
来承载,它被分成两个部分,头部是常驻在 Activity 的搜索条。下面的“搜索体”用Fragment
承载,它可能出现三种状态 1.搜索历史页 2.搜索联想页 3.搜索结果页。
Fragment 之间的切换采用 Jetpack 的Navigation
。关于 Navigation 详细的介绍可以点击Navigation 组件使用入门 | Android 开发者 | Android Developers
MVP & MVVM & MVI 架构图比对
MVI 和 MVP/MVVM 不是非此即彼的关系,它们是不同维度的。
MVP 和 MVVM 关心的是业务层的形态,MVP 中业务层用 Presenter 表达,如下图所示:
而 MVVM 中业务层用 ViewModel 表达,如下图所示:
MVI 不关心业务层形态,而是关心业务数据变换及流动的形态。
将名词解释放在一边,先来看看架构图表达形式上的差异。
MVI 的图和其他两个相比有一个显著的区别,之前使用的是{}
,比如View{Presenter{}}
表示 View 持有一个 Presenter。但 MVI 的架构图中使用的是()
,表示一个函数,即 Model 是 Intent 的函数,View 是 Model 的函数。
函数 & 函数式编程
函数即两个集合之间的一种对应关系。若对集合 x 中的值施加法则 f 后都能唯一对应集合 y 中的一个值,则说 y 是 x 的函数,记为y = f(x)
。
这里的关键是唯一自变量 x 对应唯一应变量 y。在数学中这是简单的一元函数,在编程中这是一种低复杂度,低复杂度意味着不会出错。
把一元函数进一步具象化到界面刷新这个 case 上,可以表达为 “一个 Model 唯一对应一个界面状态”,记为view = f(model)
。
按照这个思想回看一下 MVVM 架构中的函数关系(同样的问题也存在于 MVP 中),界面的状态有若干个LiveData<Model>
表达,即 viewState = f(model1, model2, model3, …),其中任何一个 model 都可以独立发生变化,而任一 model 变化后,都会引起 viewState 的变化,即所有 model 的任一排列组合与一个 viewState 对应。这个复杂度就很高,出错的概率就很大,这样的错误称为界面状态不一致,即界面状态和你预想的不一样,因为有一种排列组合没有考虑到。关于实战中界面状态不一致的实例分析可以点击“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(一)
MVI 把函数对应关系做到了极致,它把界面刷新的整个流程都表达成了一元函数。首先界面发起的动作被抽象为数据 Intent,Intent 的函数是 Model,即model = f1(intent)
,表示任一业务动作会产生唯一对应的 model,紧接着任一 Model 对应唯一界面状态,即view = f2(model)
。
f1 和 f2 这两个一元函数描述了业务意图、数据、界面状态之间一一对应的关系,在需求文档确定下来的同时,这一一对应的关系就已固定下来。
将函数的思想应用到编程,就产生了函数式编程。
函数式编程是一种编程范式,即关于如何编写程序的方法论。它的主要思想是把运算过程尽量写成一系列嵌套的函数调用。
这种编程范式最大的好处是没有副作用。副作用是指函数内部与外部互动,产生运算以外的其他结果。最典型的情况是修改全局变量。关于 MVVM 中的副作用详解可以点击“无架构”和“MVP”都救不了业务代码,MVVM能力挽狂澜?(二)。
而函数式编程中只有输入参数和返回值,不修改全局变量。从耦合的角度来看,函数式编程中的函数只包含运算且不与任何东西耦合,这使得它复杂度低、运行结果可预测、易于单元测试、调试。函数式编程是 MVI 架构相较于其他架构的一个显著不同点。
综上,使用 MVI 架构的开发过程即是:
运用函数式编程思想将需求翻译成业务意图(I)、数据(M)、界面状态(V)间的函数关系,再用响应式编程的方式将其串联成数据流的过程。
最后将函数串联的方式是响应式编程。它是一种面向数据流的编程范式。关于响应式编程的详细介绍可以点击Android 架构之 MVI 雏形 | 响应式编程 + 单向数据流 + 唯一可信数据源
除了编程范式上之外,MVI 架构还有一些其他的不同点,引用之前文章的总结:
MVI = 响应式编程 + 单向数据流 + 唯一可信数据源
关于这三条规范的剖析可以点击该系列文章:
- Android 架构之 MVI 雏形 | 响应式编程 + 单向数据流 + 唯一可信数据源
- Android 架构之 MVI 初级体 | Flow 替换 LiveData 重构数据链路
- Android 架构之 MVI 完全体 | 重新审视 MVVM 之殇,PartialChange & Reducer 来拯救
- Android 架构之 MVI 究极体 | 状态和事件分道扬镳,粘性不再是问题
其中的响应式编程会运用 Kotlin Flow,关于它的详细介绍可以点击:
总结
在具体分析 MVI 的实现细节之前,对其做一个概念性总结:
MVI 用数据流来理解界面刷新:界面是数据流的起点(生产者)也是终点(消费者),界面发出的数据叫意图,意图会用函数式编程的方式被变换为状态,最终状态通过响应式编程的方式流向界面,界面消费状态完成刷新。在这个流动的过程中,若保证了唯一可信数据源,就能实现单向数据流。
下一篇会基于搜索这个业务场景,详细展开 MVI 的实现细节。
作者:唐子玄
链接:https://juejin.cn/post/7178526966155313208
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
全套视频资料:
一、面试合集
二、源码解析合集
三、开源框架合集
Android高级架构师
由于篇幅问题,我呢也将自己当前所在技术领域的各项知识点、工具、框架等汇总成一份技术路线图,还有一些架构进阶视频、全套学习PDF文件、面试文档、源码笔记。
- 330页PDF Android学习核心笔记(内含上面8大板块)
-
Android学习的系统对应视频
-
Android进阶的系统对应学习资料
- Android BAT部分大厂面试题(有解析)
好了,以上便是今天的分享,希望为各位朋友后续的学习提供方便。觉得内容不错,也欢迎多多分享给身边的朋友哈。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!