分析并实现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的好处就是能够快速开发,在简单的页面上面使用起来非常的容易上手。所以我们到底要选择哪一种开发模式,需要看具体的场景。

相关推荐
这个DBA有点耶10 分钟前
MySQL 8.0.20移除了Block Nested Loop,之前学的JOIN优化知识还适用吗?
数据库·mysql·架构
陆柒14533 分钟前
从洋葱模型到 Elpis Core:我对 Node.js 服务端开发的理解
架构
懂软件的胡子个哥35 分钟前
微信 API 消息回调怎么设计,才能避免丢消息和重复处理
运维·微信·架构·wechatapi·个人微信号二次开发
奈斯先生Vector2 小时前
当模型版本不断变化,RelayRouter 能否帮助 AI 应用摆脱深度绑定
android·java·人工智能·开源·aigc
TimeFine2 小时前
让强模型做“总工”,让高性价比模型写代码
android
又见情义3 小时前
RK3568 Android 13 屏蔽 healthd 电池日志经验分享
android
co松柏3 小时前
一文吃透 Pi:10w stars 的极简 Agent harness
后端·架构
小聪7084 小时前
elpis-core 抽离 npm 包过程的难点和卡点
前端·架构
Bolt4 小时前
Agent: 将 harness 工程升级到认知工程
人工智能·架构·agent
晚安日记wanna4 小时前
Redis 持久化RDB 和 AOF 到底该怎么选
redis·面试·架构