MVP简单模型搭建【架构】

news2025/7/21 22:02:22

MVP简介

MVP是一种项目架构设计模式(说白了就是我们产品的一种设计方案) 其实MVP本质 就是将View和Model完全隔离,通过Presenter统一调度管理(Presenter扮演着中介的角色)传统的设计思路是我们直接跟房东谈,效率不高,累。

  • M:Model数据层,一般处理访问网络数据都在这里
  • V:View界面层,与View相关的一些操作都在这里面。View一般代表我们的Activity,Fragment,LinearLayout等等
  • P:Presenter解耦关联层 (关联Model 和 View),可能还要处理一些额外的逻辑操作,数据的处理(比如:数据的筛选等,筛选后给到我们的View去显示)

优点:

1.M层和V层完全分离,只需要通过P,V和P层的桥梁,哪个部分出现问题方便修改。只需要找对应的层级就可以  2.适合多人开发, 代码的复用性强

缺点:

1.接口回掉多,类的数量增多

MVP架构搭建流程

思维构图:

从0到1搭建MVP架构

在里面新建两个接口(Interface),分别取名 BaseView 和 BaseModel,这里定义一些公共方法

public interface BaseView {
    
    void showLoading();
    
    void hideLoading();
    
    void showError();
​
}
​
public interface BaseModel {
​
}

接下来定义一个抽象类,取名 BasePresenter

public abstract class BasePresenter<M, V> {
​
    protected M mModel;
    //弱引用的写法,避免内存泄漏。
    protected WeakReference<V> mView;
     
    protected void onAttach(M m, V v) {
        mView = new WeakReference<>(v);
        mModel = m;
    }
     
    //检测 V 是否已关联 P
    protected boolean isViewAttached() {
        return null != mView && null != mView.get();
    }
     
    protected V getView() {
        return isViewAttached() ? mView.get() : null;
    }
     
    protected void onDetach() {
        if (null != mView) {
            mView.clear();
            mView = null;
        }
    }
​
}

该类则用于反射获取指定泛型

public class ReflectUtil {
​
    public static <T> T getT(Object o, int i) {
        try {
            return ((Class<T>) ((ParameterizedType) (o.getClass().getGenericSuperclass())).getActualTypeArguments()[i]).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
​
}

接下来定义BaseActivity,举一反三BaseFragment同理

public abstract class BaseActivity<T extends BasePresenter, M extends BaseModel> extends AppCompatActivity implements BaseView {
​
    protected T mPresenter;
    protected M mModel;
     
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        //通过反射获取presenter model对象
        mPresenter = ReflectUtil.getT(this, 0);
        mModel = ReflectUtil.getT(this, 1);
        //绑定
        mPresenter.onAttach(mModel, this);
     
        initView();
    }
     
    protected abstract int getLayoutId();
     
    protected abstract int initView();
     
    @Override
    public void showLoading() {
     
    }
     
    @Override
    public void hideLoading() {
     
    }
     
    @Override
    public void showError() {
     
    }
     
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //解绑
        mPresenter.onDetach();
    }
}

创建接口 MvpListener,用于数据从 M 到 V 的层间传递

public interface MvpListener<T> {
    void onSuccess(T result);
​
    void onError(String errorMsg);
}

接下来创建一个Contract,来归纳创建view、model、presenter接口,这里可以使用插件mvphelper,省去创建类的步骤

public interface MainContract {
    interface Model extends BaseModel {
        void loadDaily(String url, MvpListener<String> listener);
    }
​
    interface View extends BaseView {
        void setData(String s);
    }
     
    abstract class Presenter extends BasePresenter<Model, View> {
        abstract void loadData(String url);
    }
}

然后实现这三层,首先是presenter

public class MainPresenter extends MainContract.Presenter {
    @Override
    protected void loadData(String url) {
        MainContract.View mView = getView();
        if (mView == null) {
            return;
        }
​
        mView.showLoading();
        //调用model方法,获取网络请求回调结果
        mModel.loadDaily(url, new MvpListener<String>() {
            @Override
            public void onSuccess(String result) {
                mView.hideLoading();
                mView.setData(result);
            }
     
            @Override
            public void onError(String errorMsg) {
                mView.hideLoading();
                mView.showError();
            }
        });
    }
}

接下来是model,我这里网络请求使用的okgo,这个根据自己喜好用什么都一样,需要在成功跟失败的回调里去调用自定义的mvplistener

public class MainModel implements MainContract.Model {
    @Override
    public void loadDaily(String url, MvpListener<String> listener) {
        //这里执行网络请求操作
        OkGo.<String>get(url).execute(new StringCallback() {
            @Override
            public void onSuccess(Response<String> response) {
                listener.onSuccess(response.body());
            }
​
            @Override
            public void onError(Response<String> response) {
                super.onError(response);
                listener.onError(response.body());
            }
        });
    }
}

最后是view,也就是我们的activity

public class MainActivity extends BaseActivity<MainPresenter, MainModel> implements MainContract.View {
​
    private static final Locale LOCALE = Locale.CHINA;
     
    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }
     
    @Override
    protected void initView() {
        mPresenter.loadData("http://news.at.zhihu.com/api/4/news/before/" + format(new Date(), "yyyyMMdd"));
    }
​
 
​
    @Override
    public void setData(String s) {
        Toast.makeText(this, "请求结果" + s, Toast.LENGTH_SHORT).show();
    }
     
    public static String format(Date date, String s) {
        return new SimpleDateFormat(s, LOCALE).format(date);
    }
}

本文意在搭建mvp,就不去做数据列表展示了,在这里做了一个toast,贴上成功的截图

全文介绍了MVP的介绍及原理;再到0至1的搭建过程;更多架构学习技术,可参考《Android核心技术手册 》点击查看。需要的获取一下。

总结

最后,到这里mvp框架就搭建完毕了,总结一下实现过程

  1. 创建baseview、basemodel、basepresenter、baseactivity基类
  2. 创建contract类创建view、model、presenter内部类编写抽象方法
  3. 创建view、model、presenter实现类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/368551.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聊聊动态线程池的9个场景(改进版)

线程池是一种基于 池化思想管理线程 的工具&#xff0c;使用线程池可以减少 创建销毁线程的开销&#xff0c;避免线程过多导致 系统资源耗尽。在 高并发以及大批量 的任务处理场景&#xff0c;线程池的使用是必不可少的。 如果有在项目中实际使用线程池&#xff0c;相信你可能…

数仓模型之维度建模

目录 1、数仓架构原则 2、如何搭建一个好的数仓 2.1 建模方法 2.2 建模解决的痛点 2.3 数仓系统满足的特性 2.4 数仓架构设计 3、维度建模 4、案例 5、问题讨论 今天我们来聊聊在数仓模型中举足轻重的维度建模。 简单而言&#xff0c;数据仓库的核心目标是为展现层提…

Hive学习——开窗函数精讲

目录 一、基于行的窗口函数——行的起点~行的终点 二、基于值的窗口函数——值的起点~值的终点 三、基于分区的窗口函数 四、基于缺省的窗口函数 五、lead与lag 六、first_value和last_value 七、排名函数——rank(113)、dense_rank(112)、row_number(123) 八、NTILE分…

nvm (node版本管理工具)安装的详细步骤,并解决安装过程中遇到的问题

1、下载NVM&#xff0c;跳转下载链接后&#xff0c;如下图&#xff0c;下载红框后解压文件 2、安装 注意&#xff1a;双击安装之后&#xff0c;会有两个地址选择&#xff0c; 1、地址中不能存在空格 2、不要放在C盘中&#xff0c;后面需要改个设置文件&#xff0c;安装到C盘的…

银行家算法

银行家算法 银行家算法是一种用来避免操作系统死锁出现的有效算法&#xff0c;所以在引入银行家算法的解释之前&#xff0c;有必要简单介绍一下死锁的概念。 一、死锁 死锁&#xff1a;是指两个或两个以上的进程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成…

Gitlab Linux 环境安装

环境检查是否已经安装了gitlab&#xff0c;安装了需要卸载# 检查当前环境是否已经安装了gitlab&#xff0c;并且查看版本 gitlab-rails console # 删除命令 yum remove git# 查找命令 rpm -qa | grep gitlab # 删除命令 rpm -e gitlab-ce-12.10.1-ce.0.el8.x86_64 # 查找命令f…

DS期末复习卷(八)

一、选择题(30分) 1.字符串的长度是指&#xff08; C &#xff09;。 (A) 串中不同字符的个数 (B) 串中不同字母的个数 (C ) 串中所含字符的个数 (D) 串中不同数字的个数 2.建立一个长度为n的有序单链表的时间复杂度为&#xff08; C &#xff09; (A) O(n) (B) O(1) © …

小米/红米手机数据恢复:从小米手机恢复已删除的数据

如果您不小心删除了小米手机上的数据&#xff0c;后来发现您需要它&#xff0c;那么本文适合您。我将向您介绍一些最可靠的小米恢复方法&#xff0c;以将您的数据恢复到您的设备上。无论您是否有备份&#xff0c;都可以处理。让我们开始吧&#xff01; 小米数据恢复 - 如何做&a…

一篇学习JVM

基础入门 1.JDK、JRE、JVM三者间的联系与区别 JDK JDK(Java SE Development Kit)&#xff0c;Java标准开发包&#xff0c;它提供了编译、运行Java程序所需的各种工具和资源&#xff0c;包括Java编译器、Java运行时环境&#xff0c;以及常用的Java类库等。 下图是JDK的安装目…

博客管理系统--项目说明

项目体验地址&#xff08;账号&#xff1a;123&#xff0c;密码&#xff1a;123&#xff09;http://120.53.20.213:8080/blog_system/login.html项目码云Gitee地址&#xff1a;https://gitee.com/GoodManSS/project/tree/master/blog_system&#xff08;一&#xff09;准备工作…

【ArcGIS Pro二次开发】(7):地图(Map)的基本操作

地图是ArcGIS Pro中的基础起点&#xff0c;也是大多数工程的基础。主要用于显示表示空间数据的图层。 一、地图(Map)的基本操作示例 1、获取当前地图 var map MapView.Active.Map; 2、获取一级图层 var lys map.Layers; 用于获取地图中的单一图层&#xff0c;以及图层组…

【正点原子FPGA连载】第十六章DP彩条显示实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十六章DP彩条显…

什么是路由?

什么是路由&#xff1f; 介绍 **路由是指路由器从一个接口上收到数据包&#xff0c;根据数据包的目的地址进行定向并转发到另一个接口的过程。**路由发生在OSI网络参考模型中的第三层即网络层。 路由引导分组转送&#xff0c;经过一些中间的节点后&#xff0c;到它们最后的目…

六【 SpringMVC框架】

一 SpringMVC框架 目录一 SpringMVC框架1.什么是MVC2.SpringMVC概述3.SpringMVC常见开发方式4.SpringMVC执行流程5.SpringMVC核心组件介绍6.快速构建Spring MVC程序✅作者简介&#xff1a;Java-小白后端开发者 &#x1f96d;公认外号&#xff1a;球场上的黑曼巴 &#x1f34e;个…

工业三防平板可应用于各种复杂苛刻的工作环境

伴随着工业互联网技术的快速发展&#xff0c;生产制造自然环境繁杂&#xff0c;机器设备规定比较严苛。普通平板在工业场景户外场景等都比较容易出现磕碰或者出现其它因素如进水、进灰尘而引发设备故障。三防平板之所以在建筑工程的应用较为广泛&#xff0c;这与其独特的性能是…

线性数据结构:数组 Array

一、前言数组是数据结构还是数据类型&#xff1f;数组只是个名称&#xff0c;它可以描述一组操作&#xff0c;也可以命名这组操作。数组的数据操作&#xff0c;是通过 idx->val 的方式来处理。它不是具体要求内存上要存储着连续的数据才叫数组&#xff0c;而是说&#xff0c…

scratch和平使者 电子学会图形化编程scratch等级考试一级真题和答案解析2022年12月

目录 scratch和平使者 一、题目要求 1、准备工作 2、功能实现 二、案例分析

视图、游标、慢查询日志

Java知识点总结&#xff1a;想看的可以从这里进入 目录2.7、视图、游标2.7.1、视图2.7.2、游标2.7、慢查询日志2.7、视图、游标 2.7.1、视图 视图是一种虚拟存在的表&#xff0c;同真实表一样&#xff0c;视图也由列和行构成&#xff0c;它不存在于数据库中&#xff0c;是我们…

【红黑树】红黑树插入操作相关的细节和疑难拆解分析

本文就红黑树的插入操作进行细致到每一个小步骤的解析。1&#xff0c;成员变量本红黑树使用了三叉链结构&#xff0c;使用的时候尤其要记得处理指向父亲的指针。为何在节点的构造函数中&#xff0c;默认节点的颜色为红色&#xff1f;因为考虑到红黑树的性质&#xff08;对于每个…

汇编语言 标志位总结

缩写原意: Overflow of = OV NV [No Overflow] Direction df = DN (decrement) UP (increment) Interrupt if = EI (enabled) DI (disabled) Sign sf = NG (negative) PL (positive) Zero zf = ZR [zero] NZ [ Not zero] Auxiliary Carry af = AC NA [ No AC ] Parity pf = PE…