一篇文章讲清楚Android中的MVC、MVP、MVVM架构 (附实现代码)

01 架构介绍

先来看一下MVC、MVP、MVVM的架构图。

从这些架构图中,可以看到每种架构都有3个模块以及数据流动方向箭头。

模块

在系统架构中,首先要做的就是把系统整体按照一定的原则划分成模块。

数据流动

模块划分之后,模块之间的通信,就是数据的流动。在Android中,流动数据包括两部分,事件和数据。

架构

模块和模块之间的数据通信方式构成不同的架构。在这3种架构中,都是把系统整体划分成了3个模块:视图层,数据层,业务层。 他们之间的区别在于,模块之间的通信方式(数据流动方向)不一致。

  • MVC是视图层接收到事件后调用到业务层处理业务逻辑,业务层调用数据层处理数据,数据层再调用视图层更新页面。
  • MVP是视图层接收到事件后调用到业务层处理,业务层调用数据层处理数据,数据层处理数据后回调给业务层,业务层再回调给视图层更新页面。(数据层已不再持有视图层,他们之间通过业务层(Presenter)交互,具体使用接口实现,使数据层和视图层解耦。
  • MVVM在MVP的基础上实现了视图层和业务层的双向数据绑定(data binding),不再通过接口的方式交互,ViewModel不在和Presenter一样持有视图层,使视图层和业务层解耦。

02 具体实现

MVC

视图层:在MVC架构中, Android的xml布局文件和Activity/Fragment文件被划分为View视图层。 因为xml作为视图层功能太弱,只能够实现页面的布局,不能够实现页面数据和事件的处理。需要和Activity一起才能够构成一个完整的视图层。

业务层:大多数的MVC架构开发的安卓项目, 并没有把Controller业务层独立出来,而是将业务层也在Activity/Fragment中实现。这导致了Activity/Fragment的代码非常臃肿,这就是MVC的缺点之一。 在本例中,我们会将业务层独立出来,实现一个标准的MVC架构。

数据层:数据层Model指的是,数据管理模块,这包括了数据的获取,处理。存储等。 MVP、MVVM的架构中的Model也是一样。后面不再赘述。

代码结构

xml代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_gallery_outer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

    <EditText
        android:id="@+id/tv_account"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_gravity="center"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="20dp"
        android:layout_marginRight="16dp"
        android:gravity="center"
        android:hint="输入用户名" />

    <EditText
        android:id="@+id/tv_pwd"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_gravity="center"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:gravity="center"
        android:hint="输入密码" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_gravity="center"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:gravity="center"
        android:text="登录" />

</LinearLayout>

Activity代码


public class MVCActivity extends AppCompatActivity {

    TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
         tvResult = findViewById(R.id.tv_result);
        TextView tvAccount = findViewById(R.id.tv_account);
        TextView tvPwd = findViewById(R.id.tv_pwd);
        Button btnLogin = findViewById(R.id.btn_login);

        MVCController mvcController = new MVCController();

        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mvcController.login(tvAccount.getText().toString(),tvPwd.getText().toString(), MVCActivity.this);
            }
        });
    }

    public void loginSuccess(){
        tvResult.setText("登录结果:登录成功");
    }

    public void loginFail(){
        tvResult.setText("登录结果:登录失败");
    }

}

Controller代码

public class MVCController {

    MVCModel mvcModel;

    public MVCController() {
        mvcModel = new MVCModel();
    }

    public void login(String account, String pwd, MVCActivity loginActivity) {
        mvcModel.login(account, pwd, loginActivity);
    }
}

Model代码

public class MVCModel {

    public void login(String account, String pwd, MVCActivity loginActivity){

        if (account == null || account.length()==0) {
            loginActivity.loginFail();
        }

        if (pwd == null || pwd.length()==0) {
            loginActivity.loginFail();
        }

        if ("user123".equals(account) && "pwd123".equals(pwd)){
            loginActivity.loginSuccess();
        }

    }

}

实现代码说明

在Activity中监听登录按钮的事件,接收到事件之后,调用Controller的登录方法处理登录逻辑,在Controller的登录方法中调用Model请求网络数据(这里是模拟)判断是否登录成功,Model拿到登录结果后,调用Activity的方法刷新页面数据,展示登录结果。

优缺点

优点:通过划分模块的方式,将系统分成了3个模块,视图层,业务层和数据层。 代码开发实现不再是只在一个代码文件中,一定程度便于程序开发。

缺点:但是三个模块之间还存在很强的耦合关系。 不利于业务需求的更变和代码维护工作。

MVP

MVP架构是基于MVC的改进,将MVC的中Controller独立出来作为Presenter。 xml和Activity还是作为视图层, 视图层接收到页面数据,调用Presenter进行业务逻辑处理,Presenter调用Model进行数据处理,Model回传数据给Presenter,Presenter回传数据给View。数据的回传通过接口回调的方式来实现。

代码结构

IModel接口代码

public interface IModel {
    public boolean login(String account, String pwd);
}

IView接口代码

public interface IView {
    public void loginSuccess();
    public void loginFail();
}

Activity代码

public class MVPActivity extends AppCompatActivity implements IView {

    TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        tvResult = findViewById(R.id.tv_result);

        TextView tvAccount = findViewById(R.id.tv_account);
        TextView tvPwd = findViewById(R.id.tv_pwd);
        Button btnLogin = findViewById(R.id.btn_login);

        MVPPresenter presenter = new MVPPresenter();
        presenter.setiView(this);
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.login(tvAccount.getText().toString(), tvPwd.getText().toString());
            }
        });
    }

    public void loginSuccess() {
        tvResult.setText("登录结果:登录成功");
    }

    public void loginFail() {
        tvResult.setText("登录结果:登录失败");
    }
}

Model代码

public class MVPModel implements IModel {
    public boolean login(String account, String pwd) {

        if (account == null || account.length() == 0) {
            return false;
        }

        if (pwd == null || pwd.length() == 0) {
            return false;
        }

        if ("user123".equals(account) && "pwd123".equals(pwd)) {
            return true;

        }
        return false;
    }
}

Presenter代码

public class MVPPresenter {

    MVPModel model;

    public MVPPresenter() {
        model = new MVPModel();
    }

    IView iView;

    public void setiView(IView iView) {
        this.iView = iView;
    }

    public void login(String account, String pwd) {
        boolean loginResult = model.login(account, pwd);

        if (loginResult){
            iView.loginSuccess();
        }else {
            iView.loginFail();
        }
    }
}

实现代码说明

定义了两个接口,IView和IModel, Activity和Model分别实现了这两个接口。 在Presenter中持有这两个实例。Presenter调用Model处理数据后,通过Iview的接口方法回调给Activity刷新页面。

优缺点

从上面的代码可以看到,三个模块之间的通信是通过接口实现的,在实际开发,定义的接口和方法会非常多。 导致很简单的一个页面功能也需要实现多个接口和方法。

优点就是通过Presenter,把MVC中的Controller代码抽出来了,并且Presenter作为View和Model通信的桥梁,完成了Model和View的解耦。

MVVM

MVVM在MVP的基础上加入了双向绑定,使View能够感知ViewModel中的数据变化,ViewModel能够感知View数据的变化。

代码结构

xml代码

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="viewModel"
            type="com.domain.android.study.notes.architecture.mvvm.MVVMViewModel" />

    </data>

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ll_gallery_outer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_result"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.result}"
            android:layout_gravity="center" />

        <EditText
            android:id="@+id/tv_account"
            android:layout_width="match_parent"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_height="40dp"
            android:hint="输入用户名"
            android:gravity="center"
            android:text="@={viewModel.account}"

            android:layout_gravity="center"
            android:layout_marginTop="20dp" />

        <EditText
            android:id="@+id/tv_pwd"
            android:layout_width="match_parent"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_height="40dp"
            android:hint="输入密码"
            android:text="@={viewModel.pwd}"
            android:gravity="center"
            android:layout_gravity="center" />

        <Button
            android:id="@+id/btn_login"
            android:layout_width="match_parent"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_height="40dp"
            android:text="登录"
            android:gravity="center"
            android:layout_gravity="center" />

    </LinearLayout>
</layout>

Activity代码

public class MVVMActivity extends AppCompatActivity {

    MVVMViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityLoginBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_login);
        viewModel = ViewModelProviders.of(this).get(MVVMViewModel.class);
        binding.setVariable(BR.viewModel, viewModel);
        binding.setLifecycleOwner(this);
        binding.btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewModel.login();
            }
        });

    }

}

ViewModel代码

public class MVVMViewModel  extends ViewModel {

    public ObservableField<String> account = new ObservableField<>("");
    public ObservableField<String> pwd = new ObservableField<>("");
    public ObservableField<String> result = new ObservableField<>("");

    MVVMModel mvvmModel;
    public MVVMViewModel() {
         mvvmModel = new MVVMModel();
    }

    public void login(){
        boolean loginResult = mvvmModel.login(account.get(), pwd.get());
        result.set(loginResult ? "登录结果:成功" :"登录结果:失败");
    }

}

Model代码

public class MVVMModel {
    public boolean login(String account, String pwd) {
        if (account == null || account.length() == 0) {
            return false;
        }

        if (pwd == null || pwd.length() == 0) {
            return false;
        }
        if ("user123".equals(account) && "pwd123".equals(pwd)) {
            return true;
        }
        return false;
    }
}

注意

在本例MVVM架构实现中,用到了Android提供的data binding这个数据双向绑定框架。需要在APP模块的gralde文件中添加以下配置开启:

 android {
 ...
 dataBinding {
        enabled true
    }
  ...
    }

实现代码说明

通过Android提供的数据双向绑定库data binding 将Acitvity/xml视图层与ViewModel绑定。在xml布局文件中,通过@{}来表示单向绑定或者@={}来表示双向绑定。Activity接受到视图层的登录点击事件后,调用ViewModel处理登录业务逻辑,ViewModel通过双向数据绑定拿到到视图层输入的账号密码数据,调用Model处理数据,Model处理数据后,回传给ViewModel, ViewModel的数据改变,View感知后刷新页面。

注意

data binding通过观察者模式实现。 内部具体实现也是通过调用notify通知数据变化给观察者,notify调用了观察者实现的接口方法。

优缺点

优点:经过数据双向绑定之后,我们不在需要想MVP中写那么多接口回调方法区实现视图层和业务层的交互。业务层也不再持有视图层的引用。

缺点:通过这种方式进行数据双向绑定后,xml中会多出一些标签、表达式、甚至和业务有点的简单计算代码。这不利于业务的逻辑的查看。并且由于双向绑定是data binding实现的。在这个过程中, 如果出现bug导致数据没有被感知改变,不方便排错,因为xml不能debug调试。

03 总结

MVC、MVP、MVVM大体上都是把系统划分成3个模块:视图层、业务层、数据层。 但是他们的通信方式、数据流动方向不一致,形成了不同的架构。 其后面产生的架构都是为了更好的解耦,解决已有架构的不足。每个架构都有自己的优缺点,没有最好的架构,只有最合适的架构。

作者:domain_sun
链接:https://juejin.cn/post/7197230639144828988

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

  • 18
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MVCMVPMVVM 是三种设计模式,用于在 Android 应用程序组织代码MVC(模型-视图-控制器):模型存储应用程序数据,视图显示数据,控制器处理用户交互。 MVP(模型-视图-presenter):与 MVC 类似,但 presenter 更加紧密地与视图绑定,负责更新视图。 MVVM(模型-视图-视图模型):与 MVP 类似,但视图模型与视图绑定,负责将数据转换为视图可用的形式。 三者的差异在于MVC会产生视图和模型之间的耦合,MVPMVVM是将视图和模型之间的耦合分离,更加灵活。 ### 回答2: Android开发MVCMVPMVVM都是常见的架构模式,用来组织Android应用的代码结构,让代码更加规范、易于维护。 MVC(Model-View-Controller)是最早的一种架构模式,它将应用分为三个模块:模型(Model)、视图(View)和控制器(Controller)。其模型负责数据的存储和操作,视图负责显示界面,控制器则负责对用户输入进行响应,协调模型和视图之间的关系。MVC模式的优点是结构清晰,各个模块职责分明,易于实现代码复用,因此广泛应用。但是MVC模式也有一些缺点,比如控制器很难进行单元测试,代码复杂度较高,难以维护大型项目等问题。 MVP(Model-View-Presenter)是一种基于MVC模式的改进,它将模型和视图分离,通过在间加上Presenter来连接两者。Presenter接受用户的输入,并根据视图的状态更新数据模型,然后更新视图显示。MVP模式的优点是易于单元测试,将业务逻辑和界面分离,代码复杂度较低,易于维护。但是对于大型项目,Presenter层也会变得庞大且复杂。 MVVM(Model-View-ViewModel)是一种结合数据绑定和命令模式的前端设计模式,它将模型、视图和ViewModel分开,通过数据绑定将视图和ViewModel联系起来。ViewModel封装了视图的状态和行为,当ViewModel被修改时,视图会自动更新。MVVM模式的优点是将视图和ViewModel解耦,通过数据绑定自动更新视图,提高了代码的可重用性。但MVVM模式需要使用大量的数据绑定,可能导致系统卡顿,同时实现较为复杂。 总的来说,MVCMVPMVVM这三种模式都有各自的适用场景。在小型项目,可以使用MVC模式;在型项目,可以使用MVP模式;在大型项目,可以使用MVVM模式。选择合适的架构模式能够让代码更易于维护,提高开发效率。 ### 回答3: Android是一种以Java为基础的开源操作系统,广泛应用于移动设备。在开发Android应用程序时,常用的三种架构模式是MVCMVPMVVMMVC是一种典型的应用程序架构模式,其M代表模型,V代表视图,C代表控制器。在AndroidMVC通常用规定ViewController或Activity来实现MVP是Model-View-Presenter的缩写,其M代表模型,V代表视图,P代表演示者。MVP将视图项分离,并引入间者Presenter,以实现界面和业务逻辑分离的目的。在AndroidMVP通常实现在Activity或Fragment上。 MVVM是Model-View-ViewModel的缩写,其M代表模型,V代表视图,VM代表视图模型。ViewModel担任间件角色,处理视图的数据,并使控制逻辑与视图分离开。在AndroidMVVM通常实现了Data Binding。 总的来说,三种架构模式都旨在将应用程序分离成各个组成部分,每个部分具有各自分离的职责,在开发Android应用程序时选择合适的架构模式,能够提高开发效率、提高代码质量、降低维护成本、提高整个应用程序的可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值