[最全]Android安卓架构MVC、MVP、MVVM之间的区别和联系(图解+案例+源码) 您所在的位置:网站首页 衰弱与衰退的区别和联系图片 [最全]Android安卓架构MVC、MVP、MVVM之间的区别和联系(图解+案例+源码)

[最全]Android安卓架构MVC、MVP、MVVM之间的区别和联系(图解+案例+源码)

2024-03-11 21:25| 来源: 网络整理| 查看: 265

一、问题背景

博主最近在准备春招面试中介绍自己简历中Android项目的MVP架构,但是博主发现若自身不彻底弄懂Android安卓架构MVC、MVP、MVVM之间的区别和联系,博主将无法准确地向面试官讲解自己Android项目的MVP架构,因此博主浏览了相关文章,做出了以下总结。

二、Android安卓架构MVC、MVP、MVVM 1.MVC(Model View Controller)

MVC各字母的全称及含义:

Model:代表我们的数据模型,管理数据状态,比如Android项目中Java Bean。View:视图,即呈现给用户的UI,比如Android项目中的layout.xml文件、Activity和Fragment。Controller:控制者,负责处理用户与app之间的交互,包含业务逻辑。所以Controller是Model与View的中介,比如Android项目中Activity和Fragment。

MVC,Model View Controller,是软件架构中最常见的一种框架。简单来说就是通过controller的控制去操作model层的数据,并且返回给view层展示,具体见下图: 在这里插入图片描述 当用户触发事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上,这就是MVC的工作原理。

1.1 MVC的优缺点

MVC缺点:

View与Model之间还存在依赖关系,Controller很重很复杂。 由上面的MVC架构图可知,view层和model层是相互可知的,这意味着两层之间存在耦合,耦合对于一个大型程序来说是非常致命的,因为这表示开发,测试,维护都需要花大量的精力。在Android中Activity即是View又是Controller,所以会很复杂。 xml作为view层,控制能力实在太弱了,你想去动态的改变一个页面的背景,或者动态的隐藏/显示一个按钮,这些都没办法在xml中做,只能把代码写在activity中,造成了activity既是controller层,又是view层的这样一个窘境。大家回想一下自己写的代码,如果是一个逻辑很复杂的页面,activity或者fragment是不是动辄上千行呢?这样不仅写起来麻烦,维护起来更是噩梦。 1.2 Android中的MVC

那具体到Android上是怎么样一个情况呢?

大家都知道一个Android工程有什么对吧,有java的class文件,有res文件夹,里面是各种资源,还有类似manifest文件等等。对于原生的Android项目来说,layout.xml里面的xml文件就对应于MVC的view层,里面都是一些view的布局代码,而各种java bean,还有一些类似repository类就对应于model层,至于controller层嘛,当然就是各种activity咯。大家可以试着套用我上面说的MVC的工作原理是理解。比如你的界面有一个按钮,按下这个按钮去网络上下载一个文件,这个按钮是view层的,是使用xml来写的,而那些和网络连接相关的代码写在其他类里,比如你可以写一个专门的networkHelper类,这个就是model层,那怎么连接这两层呢?是通过button.setOnClickListener()这个函数,这个函数就写在了activity中,对应于controller层。是不是很清晰。

大家想过这样会有什么问题吗?显然是有的,不然为什么会有MVP和MVVM的诞生呢,是吧。问题就在于xml作为view层,控制能力实在太弱了,你想去动态的改变一个页面的背景,或者动态的隐藏/显示一个按钮,这些都没办法在xml中做,只能把代码写在activity中,造成了activity既是controller层,又是view层的这样一个窘境。大家回想一下自己写的代码,如果是一个逻辑很复杂的页面,activity或者fragment是不是动辄上千行呢?这样不仅写起来麻烦,维护起来更是噩梦。(当然看过Android源码的同学其实会发现上千行的代码不算啥,一个RecyclerView.class的代码都快上万行了呢。。)

MVC还有一个重要的缺陷,大家看上面那幅图,view层和model层是相互可知的,这意味着两层之间存在耦合,耦合对于一个大型程序来说是非常致命的,因为这表示开发,测试,维护都需要花大量的精力。

正因为MVC有这样那样的缺点,所以才演化出了MVP和MVVM这两种框架。

2.MVP(Model View Presenter)

MVP各字母的全称及含义:

Model:代表我们的数据模型,管理数据状态。View:视图,即呈现给用户的UI,并且负责与客户进行交互。比如我们的XML/Activity/Fragment。Presenter:主持者,Presenter通过View接收用户的输入,然后在Model的帮助下处理用户的数据并将结果传递回View。Presenter通过接口与View进行通信。接口在presenter类中定义,它传递所需的数据。Activity/Fragment 及其他View视图组件实现此接口获得他们想要的数据并呈现数据。

MVP作为MVC的演化,解决了MVC不少的缺点,对于Android来说,MVP的model层相对于MVC是一样的,而activity和fragment不再是controller层,而是纯粹的view层,所有关于用户事件的转发全部交由presenter层处理。下面还是让我们看图: 在这里插入图片描述 从图中就可以看出,最明显的差别就是view层和model层不再相互可知,完全的解耦,取而代之的presenter层充当了桥梁的作用,用于操作view层发出的事件传递到presenter层中,presenter层去操作model层,并且将数据返回给view层,整个过程中view层和model层完全没有联系。看到这里大家可能会问,虽然view层和model层解耦了,但是view层和presenter层不是耦合在一起了吗?其实不是的,对于view层和presenter层的通信,我们是可以通过接口实现的,具体的意思就是说我们的activity,fragment可以去实现定义好的接口,而在对应的presenter中通过接口调用方法。不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试。这就解决了MVC模式中测试,维护难的问题。

当然,其实最好的方式是使用fragment作为view层,而activity则是用于创建view层(fragment)和presenter层(presenter)的一个控制器。

2.1MVP的优缺点

优点:

将View与Model解耦,方便进行单元测试。Presenter层可通过实现接口与View层通信从而避免Presenter层与View层耦合。activity和fragment不再是controller层,而是纯粹的view层。

缺点:虽然是MVC模式的演变,但Presenter依旧很‘重’很复杂。

3.MVVM(Model View ViewModel)

MVVM各字母的全称及含义:

Model:代表我们的数据模型,管理数据状态。View:视图,即呈现给用户的UI,并且负责与客户进行交互。比如我们的XML/Activity/Fragment。ViewModel:如上图所示,ViewModel与Presenter的区别,在MVVM中,View引用持有ViewModel,但ViewModel得不到任何关于View的信息。所以View与ViewModel之间存在着一对多的关系,一个View可以持有多个ViewModel。

在这里插入图片描述 从图中看出,它和MVP的区别貌似不大,只不过是presenter层换成了viewmodel层,还有一点就是view层和viewmodel层是相互绑定的关系,这意味着当你更新viewmodel层的数据的时候,view层会相应的变动ui。

三、Android安卓架构MVC、MVP、MVVM的源码实例

我们分别用MVC、MVP、MVVM设计模式来实现一个用户登入功能的界面,下方演示动图的主界面中有3个按钮,点击各个按钮将跳转到分别以MVC、MVP、MVVM架构实现的登录功能的界面,演示动图如下: 在这里插入图片描述 强烈建议您直接从该源码实例的Github网址中下载项目源码,并在Android Studio中浏览源代码并运行项目,这样即可详细地了解MVC、MVP、MVVM之间的区别与联系。

1.源码实例中的MVC架构

我们在Android Studio中可看到该源码实例项目的Android项目结构: 在这里插入图片描述 其中,该项目的MVC架构的View便是上图红框选中的activity_mvc_login.xml文件和include_login_view.xml文件;MVC架构的Controller便是MvcLoginActivity.java,而MVC架构的Model便是User.java。

MVC架构中为Model的User.java的代码如下,我们可以看到User.java是一个典型的Java Bean:

package com.example.mvcmvpmvvm.mvc.Model; public class User { private String userName; private String password; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }

MVC架构中为Controller的MvcLoginActivity.java的代码如下:

package com.example.mvcmvpmvvm.mvc.controller; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.example.mvcmvpmvvm.R; import com.example.mvcmvpmvvm.mvp.model.User; /** * @author jere */ public class MvcLoginActivity extends AppCompatActivity { private EditText userNameEt; private EditText passwordEt; private User user; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvc_login); user = new User(); userNameEt = findViewById(R.id.user_name_et); passwordEt = findViewById(R.id.password_et); Button loginBtn = findViewById(R.id.login_btn); loginBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { login(userNameEt.getText().toString(), passwordEt.getText().toString()); } }); } private void login(String userName, String password) { if (userName.equals("jere") && password.equals("123")) { user.setUserName(userName); user.setPassword(password); Toast.makeText(MvcLoginActivity.this, userName + " Login Successful", Toast.LENGTH_SHORT) .show(); } else { Toast.makeText(MvcLoginActivity.this, "Login Failed", Toast.LENGTH_SHORT) .show(); } } }

由上述MvcLoginActivity.java的代码,我们可以看到MvcLoginActivity.java既是View又是Controller。 其符合MVC的缺点:

View与Model之间还存在依赖关系,Controller很‘重’很复杂。 由上面的MVC架构图可知,view层和model层是相互可知的,这意味着两层之间存在耦合,耦合对于一个大型程序来说是非常致命的,因为这表示开发,测试,维护都需要花大量的精力。在Android中Activity即是View又是Controller,所以会很复杂。 xml作为view层,控制能力实在太弱了,你想去动态的改变一个页面的背景,或者动态的隐藏/显示一个按钮,这些都没办法在xml中做,只能把代码写在activity中,造成了activity既是controller层,又是view层的这样一个窘境。大家回想一下自己写的代码,如果是一个逻辑很复杂的页面,activity或者fragment是不是动辄上千行呢?这样不仅写起来麻烦,维护起来更是噩梦。 2.源码实例中的MVP架构

在这里插入图片描述 Model层:

public interface IUserBiz { boolean login(String userName, String password); } package com.example.mvcmvpmvvm.mvp.model; /** * @author jere */ public class User { private String userName; private String password; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } package com.example.mvcmvpmvvm.mvp.model; /** * @author jere * 其中IUserBiz的Biz代表Business */ public class UserBiz implements IUserBiz { @Override public boolean login(String userName, String password) { if (userName.equals("jere") && password.equals("123")) { User user = new User(); user.setUserName(userName); user.setPassword(password); return true; } return false; } }

Presenter层:

package com.example.mvcmvpmvvm.mvp.presenter; import com.example.mvcmvpmvvm.mvp.model.User; import com.example.mvcmvpmvvm.mvp.model.UserBiz; import com.example.mvcmvpmvvm.mvp.view.IMvpLoginView; /** * @author jere */ public class LoginPresenter{ private UserBiz userBiz; private IMvpLoginView iMvpLoginView; public LoginPresenter(IMvpLoginView iMvpLoginView) { this.iMvpLoginView = iMvpLoginView; this.userBiz = new UserBiz(); } public void login() { String userName = iMvpLoginView.getUserName(); String password = iMvpLoginView.getPassword(); boolean isLoginSuccessful = userBiz.login(userName, password); iMvpLoginView.onLoginResult(isLoginSuccessful); } }

View层:

public interface IMvpLoginView { String getUserName(); String getPassword(); void onLoginResult(Boolean isLoginSuccess); } package com.example.mvcmvpmvvm.mvp.view; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.example.mvcmvpmvvm.R; import com.example.mvcmvpmvvm.mvp.presenter.LoginPresenter; /** * @author jere */ public class MvpLoginActivity extends AppCompatActivity implements IMvpLoginView{ private EditText userNameEt; private EditText passwordEt; private LoginPresenter loginPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvp_login); userNameEt = findViewById(R.id.user_name_et); passwordEt = findViewById(R.id.password_et); Button loginBtn = findViewById(R.id.login_btn); loginPresenter = new LoginPresenter(this); loginBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { loginPresenter.login(); } }); } @Override public String getUserName() { return userNameEt.getText().toString(); } @Override public String getPassword() { return passwordEt.getText().toString(); } @Override public void onLoginResult(Boolean isLoginSuccess) { if (isLoginSuccess) { Toast.makeText(MvpLoginActivity.this, getUserName() + " Login Successful", Toast.LENGTH_SHORT) .show(); } else { Toast.makeText(MvpLoginActivity.this, "Login Failed", Toast.LENGTH_SHORT).show(); } } } 3.源码实例中的MVVM架构

在这里插入图片描述 ViewModel层:

public class LoginViewModel extends ViewModel { private User user; private MutableLiveData isLoginSuccessfulLD; public LoginViewModel() { this.isLoginSuccessfulLD = new MutableLiveData(); user = new User(); } public MutableLiveData getIsLoginSuccessfulLD() { return isLoginSuccessfulLD; } public void setIsLoginSuccessfulLD(boolean isLoginSuccessful) { isLoginSuccessfulLD.postValue(isLoginSuccessful); } public void login(String userName, String password) { if (userName.equals("jere") && password.equals("123")) { user.setUserName(userName); user.setPassword(password); setIsLoginSuccessfulLD(true); } else { setIsLoginSuccessfulLD(false); } } public String getUserName() { return user.getUserName(); } }

View层:

public class MvvmLoginActivity extends AppCompatActivity { private LoginViewModel loginVM; private EditText userNameEt; private EditText passwordEt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvvm_login); userNameEt = findViewById(R.id.user_name_et); passwordEt = findViewById(R.id.password_et); Button loginBtn = findViewById(R.id.login_btn); loginBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { loginVM.login(userNameEt.getText().toString(), passwordEt.getText().toString()); } }); loginVM = ViewModelProviders.of(this).get(LoginViewModel.class); loginVM.getIsLoginSuccessfulLD().observe(this, loginObserver); } private Observer loginObserver = new Observer() { @Override public void onChanged(@Nullable Boolean isLoginSuccessFul) { if (isLoginSuccessFul) { Toast.makeText(MvvmLoginActivity.this, loginVM.getUserName() + " Login Successful", Toast.LENGTH_SHORT) .show(); } else { Toast.makeText(MvvmLoginActivity.this, "Login Failed", Toast.LENGTH_SHORT) .show(); } } }; }

本文参考文献: [1]教你认清MVC,MVP和MVVM三者的区别 [2]MVC、MVP、MVVM,我到底该怎么选? [3]Android MVC MVP MVVM简单例子 [4]android 架构设计之MVC MVP MVVM [5]Android框架MVC、MVP和MVVM探究(图解+案例+附源码)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有