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

318 篇文章 19 订阅
46 篇文章 2 订阅

架构是什么

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

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

。架构解决了什么问题?

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

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

在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布局文件。

代码实例

<?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

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


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

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

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

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值