• 分析并实现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布局文件。

    代码实例

    
    
    
      

    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);
                    }
                }
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    上面的代码简单实现了在点击登录按钮后获取数据显示到 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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    presenter

    public interface BaseView {
    }
    
    public class BasePresenter {
        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 {
            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() {}
            });
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    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

  • 相关阅读:
    P1091 [NOIP2004 提高组] 合唱队形
    什么是离岸金融 (OFFSHORE FINANCE)
    Typescript 中根据某个字段判断其他字段是否必传
    技术面经总结
    java项目开发实例ssm流浪猫狗|流浪狗宠物救助网站
    2024年6月23日 十二生肖 今日运势
    协同存储,为边缘计算创造更大价值
    Promethus+node_exporter集群部署监控
    后端入门教程:从零开始学习后端开发
    bpa软件视频教程,BPA是什么软件
  • 原文地址:https://blog.csdn.net/weixin_61845324/article/details/133917662