让Activity更加简洁第一篇---MVP模式

2024-09-02 15:08

本文主要是介绍让Activity更加简洁第一篇---MVP模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       MVP 这种模式出现已经很久了,在网上有些关于 MVP 开源代码2014年就有了,近期有关注项目架构方面的内容,于是乎,作为一个还不懂什么是 MVP 的人,那么就一定要了解一下的。网上关于 MVP 的资料其实也不少,通常都要把 MVP 和 MVC 做一下比较,我喜欢直接了当,相信有耐心看MVP的人是一定懂 MVC 的,MVC 的略过。本文的项目地址是:https://github.com/herojing/JokeMVP ,下面结合项目谈谈MVP是个什么东西,以下就当作自己的学习总结笔记吧。

一、什么是MVP?

MVP 是 Model、Presenter、View 的缩写,三个部分的关系如下图所示。
效果图            在 Android 项目中,负责界面展示的模块(所有的 Activitiy 、Fragment以及 View 的子类)都可以划分到 View 这个层次,所有的业务逻辑处理(请求网络数据、数据库读取等)可以划分到 Model 这个层次,为了使得 View 和 Model 之间松耦合,用 Presenter 帮助解耦。所以可以猜测,在具体实现中 Presenter 类肯定要持有 View 和 Model 的引用。现在来说一下,上图中三个箭头的意思。流程是这样子的,从左到右看,比如我们刚进入一个 Activity,那么这个 Activity 做为 View 层,肯定需要通知 Presenter 加载数据,而Presenter会继续调用Model层加载数据,等Model加载完毕后,回调给 Presenter,Presenter 持有View引用,再通知View更新界面。

二、MVP的效果

       采用MVP的目的就是使得层次更加清晰,业务逻辑与 UI 分离,那么采用 MVP 以后的效果如何呢?DEMO 实现的是一个列表,效果如图下图所示,列表的内容是一些笑话信息。

如果上面的页面采用 MVP 的模式进行设计的话,那么Activity中的代码将非常清洁!请看下面。

public class MainActivity extends BaseActivity implements JokeView {// 不做分页加载的操作,所以这两个参数写死public static final String  PAGE_NUM           = "1";public static final String  PAGE_SIZE          = "20";private ListView            mListView;private JokePresenter       mJokePresenter     = null;private ArrayList<JokeInfo> mJokeInfoArrayList = null;private JokeAdapter         mJokeAdapter;@Overridepublic void initVariables() {mJokeInfoArrayList = new ArrayList<>();mJokePresenter = new JokePresenterImpl(this);}@Overridepublic void initView() {setContentView(R.layout.activity_main);mListView = (ListView) findViewById(R.id.main_page_joke_lv);}@Overridepublic void loaderData() {mJokeAdapter = new JokeAdapter(this, mJokeInfoArrayList);mListView.setAdapter(mJokeAdapter);//通知 Presenter 加载数据mJokePresenter.getJoke(PAGE_NUM, PAGE_SIZE);}@Overridepublic void showLoading() {// TODO 显示进度条}@Overridepublic void hideLoading() {// TODO 隐藏进度条}@Overridepublic void setJoke(Joke pJoke) {if (pJoke != null) {Joke.Result result = pJoke.getResult();if (result != null) {ArrayList<JokeInfo> jokeInfoArrayList = result.getJokeInfoArrayList();mJokeInfoArrayList.addAll(jokeInfoArrayList);mJokeAdapter.notifyDataSetChanged();}}}@Overridepublic void showError() {TextView errorView = new TextView(this);errorView.setTextSize(20);errorView.setText("请求失败了");mListView.setEmptyView(errorView);}
}

我重新定义了一下 Activity的“生命周期”,这个 MainActivity 继承了 BaseActivity ,BaseActivity 的实现如下:

public abstract class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initVariables();initView();loaderData();}/*** 做初始化方面的工作,比如接收上一个界面的Intent*/public abstract void initVariables();/*** 初始化控件*/public abstract void initView();/*** 加载数据*/public abstract void loaderData();}

如果你觉的还不错,那么可以继续看下面了,下面将具体阐述 MVP 三个部分是如何协同操作的。

三、View层实现

       在讲述View层实现之前,首先看一下,项目的整体结构划分,有个大致的感觉。如下图所示。感觉内容还是比较多的,但是不难,一步一步的看吧!

项目结构划分
       如果要实现上面的效果,首先做一下需求分析,每一条的笑话实体类包括的属性有笑话内容、时间;所以建立一个 Joke 实体类是很简单的。View层承担着界面的更新,MVP 中一般将界面更新的职责都交给一个 XXView ,我们的项目姑且叫做 JokeView 。当 Model 层请求到数据的时候,通知 Presenter 层后,Presenter 层就会调用 JokeView 进行界面的更新,所以需要一个设置笑话的方法;请求会有加载时间,所以界面要显示 Loading ,请求结束后需要隐藏 Loading ;当断网等异常情况发生的时候,还需要提醒用户请求发生了错误,所以还需要显示错误界面的方法。综上,定义的 JokeView 接口如下;定义好 JokeView 后,就可以让 Activity 实现 JokeView 接口,重写里面的方法进行更新了。所以我觉得在 MVP 模式开发的过程中,最先确定的就是写一个 XXView。

public interface JokeView {void showLoading();void hideLoading();void setJoke(Joke pJoke);void showError();
}

四、Model 层实现

       在 Model 层中做的主要的工作就是请求网络数据了。请求逻辑我用了 Volley ,具体可以看项目中是如何实现的,也是参考了网上一个开源代码,具体的地址记不清了 。

public class JokeModelImpl implements JokeModel {public static final String REQUEST_SERVER_URL="http://api.jisuapi.com/xiaohua/text?";public static final String APPKEY="&appkey=9814b57c706d0a23";//http://api.jisuapi.com/xiaohua/text?pagenum=10&pagesize=3&appkey=9814b57c706d0a23@Overridepublic void getJoke(String pNum, String pSize, final OnJokeListener pOnJokeListener) {VolleyRequest.newInstance().newGsonRequest(REQUEST_SERVER_URL+"pagenum="+pNum+"&"+"pagesize="+pSize+"&sort=addtime"+APPKEY,Joke.class, new Response.Listener<Joke>() {@Overridepublic void onResponse(Joke pJoke) {if (pJoke != null) {pOnJokeListener.onSuccess(pJoke);} else {pOnJokeListener.onError();}}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {pOnJokeListener.onError();}});}
}

其中 OnJokeListener 是 Presenter 层中定义的接口,用与通知 Presenter 层要调用 View 层更新数据。

public interface OnJokeListener {/*** 成功的时候回调* @param pJoke joke*/void  onSuccess(Joke pJoke);/*** 失败的时候回调*/void  onError();
}

五、Presenter 层实现

       在 Model 层和 View 层都定义好了之后,就可以写 Presenter 层了,之前已经多次说过 Presenter 层作为 Model 和 View 的桥梁,需要持有 Model 和 View 的引用。Presenter 需要实现 OnJokeListener 接口,具体的实现如下:

public class JokePresenterImpl implements JokePresenter, OnJokeListener {// P层作为M层和V层的衔接者,需要持有JokeView和JokeModel的引用private JokeModel mJokeModel = new JokeModelImpl();private JokeView  mJokeView;public JokePresenterImpl(JokeView jokeView) {mJokeView = jokeView;}/*** 调用M层取数据,getJoke由所展示的界面(Activity)调用* * @param pNum* @param pSize*/@Overridepublic void getJoke(String pNum, String pSize) {mJokeView.showLoading();mJokeModel.getJoke(pNum, pSize, this);}/*** 接收M层的回调,调用View 层进行界面的刷新**/@Overridepublic void onSuccess(Joke pJoke) {mJokeView.setJoke(pJoke);}@Overridepublic void onError() {mJokeView.showError();}
}

六、总结

最后重新梳理一下 MVP 的编写方式。
1、 根据项目需求,写一个 XXView 接口。然后让对应的 Activity/Fragment 实现这个接口。View 层基本搞定!
2、编写 Model 层,主要就是网络数据请求了或者其他什么耗时操作,实现方式尽情发挥你的想象,但是最后一定需要用 Presenter 层定义的接口,回调给 Presenter 通知 View 层 更新数据。
3、编写 Presenter 层,Presenter 层需要持有 View 层和 Model层的引用,并且实现 Presenter 层定义的回调接口。在回调接口中调用 View 层的代码 进行界面更新,最重要的是,有一个调用通过Model层的方法,在此方法中,调用 Model 层请求数据。
4、回到View 层的Activity ,调用 Presenter 层获取数据。到此完成。

       备注:为了遵守面向接口编程的原则,做了一下接口的抽取。如Presenter 中 实现了 JokePresenter 接口,Model 层中实现了 JokeModel 接口。好了,如果在阅读中,发现了有错误的地方,还望指正。

这篇关于让Activity更加简洁第一篇---MVP模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1130301

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易

使用Spring Boot集成Spring Data JPA和单例模式构建库存管理系统

引言 在企业级应用开发中,数据库操作是非常重要的一环。Spring Data JPA提供了一种简化的方式来进行数据库交互,它使得开发者无需编写复杂的JPA代码就可以完成常见的CRUD操作。此外,设计模式如单例模式可以帮助我们更好地管理和控制对象的创建过程,从而提高系统的性能和可维护性。本文将展示如何结合Spring Boot、Spring Data JPA以及单例模式来构建一个基本的库存管理系统