安卓面经(25/30)MVC、MVP、MVVM全解析
牛客高级系列专栏:
安卓(安卓系统开发也要掌握)
- 想通关安卓面试,请看(承诺免费售后答疑):《150道安卓高频面试题目录及答案链接》
- 想通关安卓系统面试,请看:《140道安卓系统Framework面试题目录及答案链接》
- 想进阶安卓开发,请看(承诺免费售后答疑):《Android进阶知识体系解析_15大安卓进阶必备知识点》
- 想了解安卓APP完整开发流程,请看(承诺免费售后答疑):《安卓APP完整开发流程》
- 想掌握安卓App性能优化,请看(承诺免费售后答疑):《安卓性能优化讲解和实战专栏》
- 想掌握Gradle语法和配置,制作Gradle插件,请看(承诺免费售后答疑):《安卓Gradle语法解析和实践大全》
嵌入式
- 想通关嵌入式面试,请看: 《111道嵌入式面试题目录及答案链接》
- 想多掌握几个嵌入式项目,请看:《6个嵌入式项目交流分享(附源码)》
本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人对常见安卓高频开发面试题的理解;
网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,承诺提供专栏内容免费技术答疑,直接咨询即可。助您提高安卓面试准备效率,为您面试保驾护航!
正文开始⬇
MVC、MVP、MVVM是安卓开发中使用较多的软件架构设计模式,特别是MVVM更是面试官喜欢提问的模式。面试官可能会问:
- 说说你对MVC、MVP、MVVM的理解,他们有什么区别和联系,如何演变的? ⭐⭐⭐⭐⭐
- MVVM的优点和缺点 ⭐⭐⭐⭐
- 为什么Activity旋转屏幕后ViewModel可以恢复数据 ⭐⭐
- ViewModel 的实例缓存到哪儿了 ⭐⭐
- 什么时候 ViewModel#onCleared() 会被调用 ⭐⭐
看完以下的解析,一定可以让面试官眼前一亮。
目录
- 1、MVC
- 2、MVP
- 3、MVVM
- 4、MVVM总结
- 4.1 MVVM的优点和缺点
- 4.2 ViewModel 的实例缓存到哪儿了
- 4.3 为什么Activity旋转屏幕后ViewModel可以恢复数据
- 4.4 什么时候 ViewModel#onCleared() 会被调用
1、MVC
如果需要设计一套人脸识别系统,用户输入自己姓名后,站在机器前面,机器就可以自动拍照并识别出用户的性别。程序员小帅不考虑软件架构,直接动手撸代码,最终功能虽然实现了,但是各种业务代码都写在同个文件里。过了一段时间,领导让小帅新增识别年龄的功能时,才发现代码非常臃肿,不利于二次开发。看过本文后,小帅重新设计了代码的架构:
- View:界面相关,将计人脸识别系统UI界面相关代码抽离出来,对应于xml布局文件;
- Controller:控制相关,将和UI界面操作相关以及判断相关的业务逻辑也抽离出来,比如判断用户是否输入姓名了,没有输入则不会开始采集用户照片等,对应于Activity;
- Model:数据相关,具体的性别识别算法运算等较为复杂的运算,本地数据的维护等;
其中View和Model,一个单独负责界面,一个负责处理数据,比较好理解。而Controller就是接收View的指令,做一些逻辑判断或者调用Model做复杂运算后,再把结果反馈给View。通过如此分工,写页面,写业务逻辑,数据运算三者相互分离。
然而,在实际的Android开发中,View层对应xml布局文件,其实能做的事情特别少,实际上关于该布局文件中的数据绑定的操作,事件处理的代码都在Activity中,造成了Activity既像View又像Controller,使得Activity变得臃肿。
而且如果不涉及复杂的运算,那么Controller处理完简单的逻辑判断后就直接返回给View。甚至View可以跳过Controller,直接和Model进行交互。这就造成,本来Controller本来就应该依赖View和Model,而现在View也依赖Controller和Model,耦合性还是太高了,于是我们希望View和Model之间要彻底断开联系。
2、MVP
在MVC的基础上,用Presenter代替Controller,此时MVP具体为:
- View:不仅负责UI界面相关操作,还要负责用户交互,相当于Activity;
- Model:依然主要负责数据处理;
- Presenter:负责View和Model之间的交互;
首先,明确下理解,在MVC中的View相当于布局文件,而在MVP中View相当于Activity;此时View和Model不再直接交互,而是使用Presenter作为二者交互的桥梁。Presenter里同时持有View和Model的引用,View也有Presenter的引用,但没有Model的引用。
当View层中某个UI界面发起某个数据操作时,会调用Presenter的引用,Presenter再调用Model层的引用请求数据。当Model层的数据处理完后会调用Presenter层的回调通知Presenter层数据加载情况,最后Presenter层再调用View层的接口将加载后的数据展示给用户看。Model层是不会直接和View层产生通讯的。
如果想看看基于MVP写的代码,可以看看这个:MVPdemo
3、MVVM
如果你是做安卓系统开发,那么你可能会接触到MVC或者MVP,而不需要用到MVVM。但如果你是安卓应用开发,那么一定要懂得MVVM。
在MVP中,Presenter更新View也需要很多烦人的代码,有没有什么方法,告诉View去监听某个数据,该数据发生变化时,View自动跟着变化呢?当然是有的,ViewModel随之诞生。ViewModel代替了Presenter,MVP变成了MVVM:Model-View-ViewModel。
- Model:和MVP中的Model一样,还是用来处理数据的;
- View:还是用来更新和处理UI界面以及和用户交互,相当于Activity。和MVP里的View的区别在于,View界面的更新从由Presenter驱动,变成了自动监听数据,随着数据变化而自动更新;
- ViewModel:Model和View的中介,处理逻辑中转任务的媒介。一个View可以绑定多个不同的ViewModel,一个ViewModel也可以被多个View同时绑定。
那么,MVVM是如何做到View的自动更新呢?在此之前,需要掌握几个新概念:
- LifeCycle:LifeCycle是Google官方提供的管理生命周期事件的方法,可以更加方便地监听声明周期变化事件;
- LiveData:这是一种用来持有数据的对象,可以设置多个观察者监听LiveData对象,当数据发生改变时,会通知处于active状态(Started和Resume状态)的观察者,并执行设置好的动作。举个例子,我们可以提前设置ActivityA,ActivityB,FragmentA,这三者分别都去监听一个变量名为studentName的LiveDataA对象,也就是在这几个类里,都有下面几行代码。当studentName数值发生改变时,就设置tv_name控件的text改为studentName的新值。那么,当studentName发生改变时,假设ActivityA和FragmentA刚好处于active状态,则ActivityA和FragmentA就会执行tv_name.text = it,自动的修改控件的文本内容。而ActivityB不处于active状态,则不会有任何操作。
myViewModel.studentName.observe(this) {
tv_name.text = it
}
- DataBinding:这是Googel发布的一个用来支持MVVM模式的框架。主要用来降低布局和逻辑的耦合度。以前都是在xml布局文件写好控件后,在Activity通过findViewById()方法绑定控件后,对控件做操作。而随着DataBinding的产生,我们可以直接在xml布局文件里直接将控件和数据绑定在一起,当数据改变时,控件自动更新。
结合LiveData+DataBinding举个例子增进理解,以下例子参考于MVVMDemo ,读者可以下载该开源项目代码实际运行看看:
首先看看布局文件:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
>
<data>
<!-- 1 -->
<variable
name="image"
type="com.zw.mvvmdemo.bean.ImageUrlBean.UrlBean"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/myImageView"
<!-- 2 -->
imageUrl="@{image.BASE_IMAGE_ADDRESS_URL + image.url}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="200dp" />
</android.support.constraint.ConstraintLayout>
</layout>
首先看[注释1],可以创建<data>变量:
<variable
name="image"
type="com.zw.mvvmdemo.bean.ImageUrlBean.UrlBean"/>
在variable标签中:
- name:需要绑定数据的名称,名称可自定义;
- type:需要绑定数据的类型;
所以,我们创建了一个名为“image”的<data>变量,并在[注释2]中使用,赋值给了另一个叫imageUrl的属性。imageUrl属性是我们自定义的一个属性,是通过DataBinding的注解BindingAdapter来声明的。
public class GetBingImageAdapter {
@BindingAdapter("imageUrl")
public static void setImage(ImageView iv, String url) { //3
Glide.with(iv)
.load(url)
.into(iv);
}
}
所以当[注释1]名为“image”的变量发生改变时,[注释2]名为“myImageView”的控件中的imageUrl属性就会随着改变,并调用[注释3]的回调函数setImage()方法,最终执行Glide这个第三方图片加载框架来刷新图片。
那么就剩下最后一个问题,[注释1]名为“image”的变量什么时候会发生改变呢?我们可以在Activity中监听从网络获取到的图片的url地址,当url地址改变时,修改“image”变量的值:
mViewModel.getImageUrl().observe(this, new Observer<UrlData<ImageUrlBean.UrlBean>>() {
@Override
public void onChanged(@Nullable UrlData<ImageUrlBean.UrlBean> data) {
mDialog.dismiss();
if(data.getErrorMsg() != null) {
Toast.makeText(BingImageActivity.this, data.getErrorMsg(),
Toast.LENGTH_LONG).show();
}
binding.setImage(data.getData()); //4
}
});
其中getImageUrl()返回的变量的定义是:
private MutableLiveData<UrlData<ImageUrlBean.UrlBean>> mData;
没错,就是一个LiveData对象。最后通过[注释4]来修改“image”变量的值。有一个知识点要注意,如果“image”的名字改为“myImageValue”,则[注释4]的函数名应该同步改为setMyImageValue()。
具体的项目源码有兴趣的同学自行下载研究:MVVMDemo 。讲到这里,大家应该就明白所谓的View能自动更新,其实是因为我们提前设置好了监听,也设置好了监听的对象数值改变后,View需要完成什么动作。
4、MVVM总结
4.1 MVVM的优点和缺点
总的来说,MVVM还是一个非常优秀的模式,主要体现在:
- 数据和布局双向绑定,我们只需要关心数据数值的改变,而不再需要操心findViewById和setText()等繁复的代码的工作;
- 一个View可以绑定多个ViewModel,一个ViewModel可以供多个View绑定,提高复用性和灵活性;
- 自带生命周期管理,不用担心因为生命周期而出现bug;
当然,MVVM也有缺点:
- View和ViewModel独立,如果出现bug定位问题较难;
- Binding类的生成可能需要多次Rebuild的操作,若Binding类过多,则编译工作会耗时很大;
- 需要提前设置好数据监听,如果数值多,那就要设置很多监听;
- 如果ViewModel层数据未改变,但却强制要View层改变UI控件时,就比较麻烦;
4.2 ViewModel 的实例缓存到哪儿了
如果我们修改了系统语言再回到App,或者旋转了屏幕,都会发现APP中当前Activity重新创建了,但是ViewModel里面的LiveDa
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
#提供免费售后答疑!!花一杯奶茶的钱获得安卓面试答疑服务,稳赚不赔# Android发展已经很多年,安卓资料网上千千万,本专栏免费提供专栏内容技术答疑!!私聊当天必回。在阅读过程或者其他安卓学习过程有疑问,都非常欢迎私聊交流。