MVP架构由浅入深篇一(基础版)

MVP架构由浅入深篇一

前言:不得不说,才开始学习MVP架构各种接口的调用和解耦代码真的让人眼花缭乱,对于很多问题都是一知半解:

  • 关于如何在Activity中高效的复用Presenter和View;
  • Mode层定义到什么程度才算是比较理想的解耦;
  • Model层与Presenter层如何比较优雅的相互通信。

所以决定静下心来理解一下该架构的艺术。博客主要参考https://www.jianshu.com/p/5c3bc32afa36?utm_campaign=haruki,其中加入自己的理解和代码实现来学习和验证MVP架构的使用技巧。


目录

MVP架构由浅入深篇一

一、MVP架构概述

1.为什么要使用MVP架构?

2.MVP理论知识

二、基础版MVP代码实现

1.文件结构

2.Callback接口

3.Model 类

4.View 接口

5.Presenter类

6.布局文件

7.MainActivity

8.运行结果:(以成功请求数据为例)

三、基础版MVP问题分析

场景1:业务逻辑完全相同

场景2、3:包含部分相同业务逻辑

场景4

场景5

基础版MVP总结


 

一、MVP架构概述

1.为什么要使用MVP架构?

MVP(Model、View、Presenter)模式将Activity中的业务逻辑分离出来,避免了Activity逻辑的高耦合,可以把Model理解成房东,View就是找房的自己,Presenter就是中介,让Activity只做UI的功能,把其他功能抽出去让其他层来完成,缺点就是代码量增加了,但是带来的优点远超缺点,尤其是项目比较大的时候更是事半功倍。

2.MVP理论知识

在MVP架构中跟MVC类似分为三层。

  1. Activity和Fragment视为View层   -->   理解为四处找房的自己
  2. Presenter为业务处理层,既能调用UI逻辑,又能请求数据   -->   相当于中介公司
  3. Model层中包含着具体的数据请求,数据源   -->   相当于房东

三层之间调用顺序为view-->presenter-->model,不能反向调用和跨级调用

由上图可知,Model层通过Callback反馈数据给Presenter层,Presenter层通过View反馈操作给Activity层。其中View和Callback都是以接口的形式存在。

  • Callback中定义了请求数据时反馈的各种状态:成功、失败、错误等
  • View中定义了Activity的具体操作,主要是将请求得到的数据在界面上更新

二、基础版MVP代码实现

因为是模拟网络数据请求,所以有三个请求数据的按钮分别对应成功、失败、异常三种不同的反馈状态。

1.文件结构

2.Callback接口

因为Callback接口是presenter和model打交道的接口,所以接口中定义了请求数据的方法

package com.example.mvpapplication;

/**
 * callback负责presenter和model交互
 * 相当于:中介和房东交互接口
 */
public interface MvpCallback {
    /**
     * 请求数据成功
     * @param data
     */
    void onSuccess(String data);

    /**
     * 使用网络API接口请求,请求数据失败
     * @param msg
     */
    void onFailure(String msg);

    /**
     * 请求数据时发生错误
     */
    void onError();

    /**
     * 请求数据完成
     */
    void onComplete();
}

3.Model 类

Model 类中定了具体的网络请求操作。利用postDelayed方法模拟耗时操作,通过判断请求参数反馈不同的请求状态:(房东)

package com.example.mvpapplication;

import android.os.Handler;

public class MvpModel {
    /**
     * 获取网络数据
     * @param param  请求参数
     * @param callback  数据回调接口 -- callback相当于房东如果有房子就要回复给中介
     */
    public static void getNetData(final String param,final MvpCallback callback){
        //利用postDelayed方法模拟网络请求数据的操作
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                switch (param){
                    case "normal":
                        callback.onSuccess("根据参数"+param+"的请求网络数据成功");
                        break;
                    case "failure":
                        callback.onFailure("请求数据失败");
                        break;
                    case "error":
                        callback.onError();
                        break;
                }
                callback.onComplete();
            }
        },2000);
    }
}

4.View 接口

View接口是Activity与Presenter层的中间层,它的作用是根据具体业务的需要,为Presenter提供调用Activity中具体UI逻辑操作的方法。相当于我和中介之间的交易

package com.example.mvpapplication;

/**
 * 这里相当于找房子的自己--对UI进行操作的接口
 */
public interface MvpView {
    /**
     * 显示正在加载数据进度
     */
    void showLoading();

    /**
     * 隐藏进度
     */
    void hideLoading();

    /**
     * 展示数据
     * @param data
     */
    void showData(String data);

    /**
     * 显示数据错误原因回调接口
     * @param msg
     */
    void showFailureMessage(String msg);

    /**
     * 当数据错误时回调接口
     */
    void showErrorMessage();
}

5.Presenter类

Presenter类是具体的逻辑业务处理类,负责请求数据,并对数据请求的反馈进行处理。Presenter相当于中介的作用,所以里面要有MvpView和Callback的声明。

package com.example.mvpapplication;

/**
 * 这里相当于中介的作用
 */
public class MvpPresenter {
    //因为中介要和雇主打交道,所以要声明MvpView
    private MvpView mView;
    public MvpPresenter(MvpView view){
        this.mView = view;
    }

    /**
     * 相当于帮我找房子--请求数据
     * @param param
     */
    public void getData(String param){
        //显示正在加载进度条
        mView.showLoading();
        //调用Model请求数据
        MvpModel.getNetData(param, new MvpCallback() /*开始和Model打交道的接口*/{
            @Override
            public void onSuccess(String data) {
                //调用view接口显示数据
                mView.showData(data);
            }

            @Override
            public void onFailure(String msg) {
                mView.showFailureMessage(msg);
            }

            @Override
            public void onError() {
                mView.showErrorMessage();
            }

            @Override
            public void onComplete() {
                mView.hideLoading();
            }
        });
    }
}

6.布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="点击按钮获取网络数据"/>


    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取数据【成功】"
        android:onClick="getData"
        />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取数据【失败】"
        android:onClick="getDataForFailure"
        />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取数据【异常】"
        android:onClick="getDataForError"
        />

</LinearLayout>

7.MainActivity

在MainActivity中,主要是对MvpView的实现,进行UI操作

package com.example.mvpapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements MvpView{

    //进度条
    ProgressDialog progressDialog;
    TextView text;
    //找到中介
    MvpPresenter presenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = findViewById(R.id.text);
        //初始化进度条
        progressDialog = new ProgressDialog(this);
        progressDialog.setCancelable(false);
        progressDialog.setMessage("正在加载中...");
        //初始化presenter
        presenter = new MvpPresenter(this);
    }

    /**
     * button事件
     */
    public void getData(View view){
        presenter.getData("normal");
    }
    public void getDataForFailure(View view){
        presenter.getData("failure");
    }
    public void getDataForError(View view){
        presenter.getData("error");
    }

    @Override
    public void showLoading() {
        if (!progressDialog.isShowing()){
            progressDialog.show();
        }
    }

    @Override
    public void hideLoading() {
        if (progressDialog.isShowing()){
            progressDialog.dismiss();
        }
    }

    @Override
    public void showData(String data) {
        text.setText(data);
    }

    @Override
    public void showFailureMessage(String msg) {
        Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
        text.setText(msg);
    }

    @Override
    public void showErrorMessage() {
        Toast.makeText(this,"请求异常",Toast.LENGTH_SHORT).show();
        text.setText("请求异常");
    }
}

8.运行结果:(以成功请求数据为例)

至此,基础版MVP已经完成了,下面我们来分析一下基础版存在的问题和如何优化?

三、基础版MVP问题分析

通过上面的代码实现,看似已经完成了MVP的框架了,但是远远不够,其中一个问题就是复用问题。

由于上述例子我们只有一个业务逻辑,即只有一个Activity,那如果有两个或者更多Activity呢?我们需要创建N多个MVP框架吗?当然在不需要MVP的Activity中当然不用创建,可是当需要MVP的Activity呢?当然这也要分情况,如果Activity业务逻辑相似当然可以复用,但是当业务逻辑不一样时,就必须创建另一个MVP了。可是又如何复用业务逻辑相似的MVP呢?请看下述分析:

场景1:业务逻辑完全相同

这种场景很简单,由于业务逻辑完全相同,就直接复用就好了。

场景2、3:包含部分相同业务逻辑

场景2和场景3的逻辑类似,都属于一个业务逻辑中包含另外一个可以单独存在的业务逻辑,这种情况采用继承的方法即可。

场景4

场景4中Activity C想要同时调用独立服务于Activity A 和 Activity B的业务逻辑,只需要将两个业务逻辑对应的Presenter分别实例化并调用业务方法即可。

场景5

场景5属于场景3与场景4的结合体,同样需要先把A和B的业务逻辑拆分开,然后同时调用。

基础版MVP总结

从上述的分析可知,基础版MVP存在复用问题。由于MVP框架还算是比较繁重的,所以复用很有必要,可以减少很多没必要的重复代码。我们能想到的方法就是类比Binder连接池,在Presenter层写完整的业务逻辑,然后通过不同的业务标志进行不同的业务处理,这种方式很简单,但是这样的话,可能会有一定的问题,比如Presenter层业务过于繁重,维护较难等。毕竟架构师提出的复用方案是实践得出的真理,存在即是合理的。在下一篇中,我们将介绍进阶版MVP框架的实现。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MVP(Model-View-Presenter)是一种常用的软件架构模式,用于实现应用程序的分层和解耦。以下是一段描述应用MVP架构的话术: "MVP架构是一种经典的软件架构模式,它将应用程序分为三个主要组成部分:模型(Model)、视图(View)和展示器(Presenter)。 首先,模型(Model)负责处理数据和业务逻辑。它包含了数据的获取、存储、处理和管理等功能。模型可以与数据库、网络或其他数据源进行交互,从而提供数据给视图使用。 其次,视图(View)是用户界面的展示层。它负责显示数据,并与用户进行交互。视图可以是用户界面的各种形式,如图形界面、命令行界面或移动应用界面等。视图将用户的操作传递给展示器,并将展示器返回的数据显示给用户。 最后,展示器(Presenter)充当了模型和视图之间的中间人。它负责处理用户的输入、业务逻辑的处理和数据的交互。展示器从视图接收用户的操作,并将其转发给模型进行处理。同时,展示器也从模型获取数据,并将其传递给视图进行展示。 MVP架构的优势在于它明确了各个组件的职责,使代码更加模块化和可维护。它将业务逻辑与用户界面分离,使得开发人员可以独立地开发和测试各个组件。此外,MVP架构还方便了应用程序的扩展和修改,因为修改一个组件不会影响其他组件的功能。 总而言之,MVP架构通过将应用程序分层和解耦,提供了一种可靠、可扩展和可维护的结构。它在许多应用程序中得到广泛应用,帮助开发人员构建高质量的软件。" 希望以上的描述能够对你理解MVP架构有所帮助!如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值