分析并实现Android中的MVC、MVP架构模式

架构是什么

架构是为了解决特定的问题而提出来的,而且它还有特定的规则,能够把整个应用的整体进行角色的划分。并且他还能够约定角色之间的联系沟通机制。

所以学习架构要带着以下三个问题去理解:

。架构解决了什么问题?

。架构模式是如何划分角色的?

。角色间是如何建立联系的?

在Android当中,经常被大家提及到就是MVC、MVP和MVVM。本文来分析一下MVC、MVP各自是怎么实现的,怎么写的,以及解决了什么问题而提出来的。

MVC

什么是MVC架构

MVC的话它本来不属于Android的架构模式,而是来自于web前端。在Android发展的前期照搬了前端这一套模式。

MVC模式就是Model、View和Controller。View的职责就是处理显示相关的逻辑以及接收用户行为。再把用户行为转发到Controller,Controller再根据请求去更新或者是获取Model层的数据。Controller更像是一个中转站或者是调度站。Model 负责管理数据、执行业务逻辑。MVC在前端的作用是为了分离数据和视图这两层,但是在Android上面它就不灵光了。

在Android语境下,这里的Controller一般特指Activity和Fragment。而Model可以是 Java 类、数据库、网络请求或其他数据源,就是负责数据的读取操作的。而View的话一般来说是指XML布局文件。

代码实例

view

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".mvc.MvcActivity">

  <Button
    android:id="@+id/bt_mvc_login"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="20dp"
    android:text="登录" />

  <TextView
    android:id="@+id/tv_mvc_response"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/bt_mvc_login"
    android:layout_marginTop="20dp"
    android:padding="5dp"
    android:text="data:"/>

</androidx.constraintlayout.widget.ConstraintLayout>

model

java 复制代码
public class LoginModel {

    private static final String TAG = "LoginModel";

    private static final String URL = "https://api.cdnjs.com/libraries/jquery/3.5.1";

    private OnLoginListener mListener;

    public interface OnLoginListener {
        void onSuccess(String data);
        void onFail();
    }


    public void login(OnLoginListener listener) {
        mListener = listener;

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(URL)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d(TAG, "onFailure");
                if(null != mListener){
                    mListener.onFail();
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String message = response.body().string();
                Log.d(TAG, "onResponse:" + message);
                if(null != mListener){
                    mListener.onSuccess(message);
                }
            }
        });
    }
}

control

typescript 复制代码
public class MvcActivity extends AppCompatActivity {

    private static final String TAG = "MvcActivity";

    private LoginModel model;

    private Button button;
    private TextView textView;

    private Handler mHandler = new Handler();

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

        button = findViewById(R.id.bt_mvc_login);
        textView = findViewById(R.id.tv_mvc_response);

        model = new LoginModel();

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //请求数据
                model.login(new LoginModel.OnLoginListener() {
                    @Override
                    public void onSuccess(String data) {
                        //更新UI
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                updateView(data);
                            }
                        });
                    }

                    @Override
                    public void onFail() {

                    }
                });
            }
        });
    }

    private void updateView(String data) {
        textView.setText(data);
    }
}

上面的代码简单实现了在点击登录按钮后获取数据显示到 TextView。

缺点

很明显,这种开发模式它的缺点就是当页面逻辑复杂时,容易导致Activity的代码膨胀。可能一个Activity当中它的代码量分分钟可以标到上千行。如果要修改某一处业务逻辑的话,有可能去找某个方法就要找半天,原因是Layout布局无法帮助Controller分担数据绑定的逻辑。

Activity虽然能够作为一个很称职的MVC Controller,但是作为一个类来说,它的职责太多了,需要实现的代码也太多了。首先从性能角度出发,Activity在使用期间会有大量的时间驻留在内存中,如果它的代码太多,就会导致性能问题。第二个也是最重要的,就是从分层架构的角度来说。如果某个层次过厚是不利于解耦的,我们就需要对这个层进行更细的拆分。

MVP

什么是MVP架构

后来为了解决Activity任务过于繁重,数据层与视图层交织在一起的问题,演化出来的MVP模式。它的主要特性就是让视图层和数据层分离。

Activity 和 Fragment 视为View层,负责处理 UI和用户交互;

Presenter 为业务处理层,负责处理业务逻辑和发起数据的请求;

Model 层中包含着具体的数据请求,数据源。

这三者之间的关系是View调用Presenter,然后再调用Model去完成数据的请求动作。Model通过callback把数据回传给Presenter,然后Presenter再通过他持有的View接口,把数据回传到View层更新UI。

代码实例

将上面的mvc改成mvp

view

typescript 复制代码
public class MvpActivity extends AppCompatActivity implements LoginContract.View{

    private static final String TAG = "MvpActivity";

    private LoginPresenter loginPresenter;

    private Button button;
    private TextView textView;

    private Handler mHandler = new Handler();

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

        button = findViewById(R.id.bt_mvc_login);
        textView = findViewById(R.id.tv_mvc_response);

        loginPresenter = new LoginPresenter();
        loginPresenter.attach(this);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                loginPresenter.getUserInfo();
            }
        });
    }

    @Override
    public void onResult(String data) {
        Log.d(TAG, "onResult data:" + data);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textView.setText(data);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //释放
        loginPresenter.detach();
    }
}

presenter

scala 复制代码
public interface BaseView {
}

public class BasePresenter<IView extends BaseView> {
    protected IView view;
    /**
     * 绑定view
     * @param view
     */
    public void attach(IView view) {
        this.view = view;
    }
    public void detach() {
        view = null;
    }
}


public interface LoginContract {

    interface View extends BaseView {
        void onResult(String data);
    }

    //定义的每个方法都会在view结构当中存在与之相对应的回调方法
    abstract class Presenter extends BasePresenter<View> {
        abstract void getUserInfo();
    }

}


public class LoginPresenter extends LoginContract.Presenter {

    private static final String TAG = "LoginPresenter";

    @Override
    void getUserInfo() {

        LoginModel model = new LoginModel();
        model.login(new LoginModel.OnLoginListener() {
            @Override
            public void onSuccess(String data) {
                view.onResult(data);
            }

            @Override
            public void onFail() {}
        });

    }
}

model

...

缺点

MVP这种开发模式对于简单的应用程序可能会显得过于复杂,MVP需要开发额外的Presenter类,可能增加开发工作量。为了实现MVP,通常需要定义大量的接口,这可能增加代码的复杂性。

总结

虽然MVP是MVC的优化后的产物,但还是各有利弊的。MVP解决了MVC在复杂项目中导致的Activity代码膨胀和维护难的问题。MVP复用代码的难度更低,实现方式替换起来更灵活。但是MVC的好处就是能够快速开发,在简单的页面上面使用起来非常的容易上手。所以我们到底要选择哪一种开发模式,需要看具体的场景。

相关推荐
沛沛老爹26 分钟前
服务监控插件全览:提升微服务可观测性的利器
微服务·云原生·架构·datadog·influx·graphite
huaqianzkh1 小时前
了解华为云容器引擎(Cloud Container Engine)
云原生·架构·华为云
消失的旧时光-19432 小时前
kotlin的密封类
android·开发语言·kotlin
Kika写代码2 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
刘某某.2 小时前
使用OpenFeign在不同微服务之间传递用户信息时失败
java·微服务·架构
迪捷软件2 小时前
知识|智能网联汽车多域电子电气架构会如何发展?
架构·汽车
zyhJhon2 小时前
软考架构-层次架构风格
架构
nbsaas-boot2 小时前
架构卡牌游戏:通过互动与挑战学习系统设计的创新玩法
学习·游戏·架构
Casual_Lei3 小时前
ClickHouse 的底层架构和原理
clickhouse·架构
服装学院的IT男3 小时前
【Android 13源码分析】WindowContainer窗口层级-4-Layer树
android