最近回顾了一下MVP框架,结合阅读到的几篇不错的博客,自己整理了一份可用于实际工作的MVP框架示例代码,这里做个记录,也顺便和网友们分享一下。

代码示例演示的是一个输入员工号查询员工信息并显示的场景,查询后的界面如下:

本文以该场景举例来搭建一个可以通用的MVP架构,代码整体结构如下:

具体的代码及结构说明:

mvpbase:所有MVP业务通用的方法

BaseModel.java

 1 package com.song.mvpdemo.mvpbase.model;
2
3 import java.util.Map;
4
5 /**
6 * 该类抽象出不同业务获取数据的通用方法
7 */
8 public abstract class BaseModel<T> {
9 //数据请求参数
10 protected String[] mParams;
11
12 /**
13 * 设置数据请求参数
14 *
15 * @param args 参数数组
16 */
17 public BaseModel params(String... args) {
18 mParams = args;
19 return this;
20 }
21
22 /**
23 * 添加Callback并执行数据请求,具体的数据请求由子类实现
24 */
25 public abstract void execute(ModelCallback<T> modelCallback);
26
27 /**
28 * 执行Get网络请求,此类看需求由自己选择写与不写
29 */
30 public void requestGetApi(String url, ModelCallback<T> modelCallback) {
31 //这里写具体的网络请求
32 }
33
34 //执行Post网络请求,此类看需求由自己选择写与不写
35 public void requestPostApi(String url, Map params, ModelCallback<T> modelCallback) {
36 //这里写具体的网络请求
37 }
38 }

ModelCallback.java

 1 package com.song.mvpdemo.mvpbase.model;
2
3 /**
4 * Presenter层调用Model层后数据回调
5 */
6 public interface ModelCallback<T> {
7 void onSuccess(T result);
8
9 void onFailOrError();
10
11 void onCompleted();
12 }

DataModel.java

 1 package com.song.mvpdemo.mvpbase.model;
2
3 /**
4 * 该类用于创建具体的业务Model
5 */
6 public class DataModel {
7 public static BaseModel createModel(Class clazz) {
8 BaseModel model = null;
9 try {
10 model = (BaseModel) clazz.newInstance();
11 } catch (IllegalAccessException e) {
12 e.printStackTrace();
13 } catch (InstantiationException e) {
14 e.printStackTrace();
15 }
16 return model;
17 }
18 }

BasePresenter.java

 1 package com.song.mvpdemo.mvpbase.presenter;
2
3 import com.song.mvpdemo.mvpbase.view.IBaseView;
4
5 /**
6 * 不同业务Presenter层通用的操作
7 */
8 public class BasePresenter<V extends IBaseView> {
9 private V mView;
10
11 public void attachView(V baseView) {
12 mView = baseView;
13 }
14
15 public void dettachView() {
16 mView = null;
17 }
18
19 public boolean isViewAttached() {
20 return mView != null;
21 }
22
23 public V getView() {
24 return mView;
25 }
26 }

IBaseView.java

1 package com.song.mvpdemo.mvpbase.view;
2
3 public interface IBaseView {
4 void showLoading();
5
6 void hideLoading();
7
8 void showFailOrError(String msg);
9 }

BaseActivity.java

 1 package com.song.mvpdemo.mvpbase.view;
2
3 import android.app.ProgressDialog;
4 import android.os.Bundle;
5
6 import androidx.appcompat.app.AppCompatActivity;
7
8 import com.song.mvpdemo.mvpbase.presenter.BasePresenter;
9
10 public abstract class BaseActivity extends AppCompatActivity implements IBaseView {
11
12 private ProgressDialog mProgressDialog;
13
14 @Override
15 protected void onCreate(Bundle savedInstanceState) {
16 super.onCreate(savedInstanceState);
17 initPresenter();
18 if (getPresenter() != null) {
19 getPresenter().attachView(this);
20 }
21
22 mProgressDialog = new ProgressDialog(this);
23 mProgressDialog.setCancelable(false);
24 mProgressDialog.setMessage("Loading...");
25 }
26
27 @Override
28 public void showLoading() {
29 if (mProgressDialog != null && !mProgressDialog.isShowing()) {
30 mProgressDialog.show();
31 }
32 }
33
34 @Override
35 public void hideLoading() {
36 if (mProgressDialog != null && mProgressDialog.isShowing()) {
37 mProgressDialog.dismiss();
38 }
39 }
40
41 /**
42 * 初始化Presenter的实例,子类实现
43 */
44 protected abstract void initPresenter();
45
46 /**
47 * 获取Presenter实例,子类实现
48 */
49 protected abstract BasePresenter getPresenter();
50
51 @Override
52 protected void onDestroy() {
53 super.onDestroy();
54 if (getPresenter() != null) {
55 getPresenter().dettachView();
56 }
57 }
58 }

StaffInfo.java

 1 package com.song.mvpdemo.staffinfo.model;
2
3 public class StaffInfo {
4 private String staffId;
5 private String name;
6 private int age;
7 private float salary;
8
9 public StaffInfo(String staffId, String name, int age, float salary) {
10 this.staffId = staffId;
11 this.name = name;
12 this.age = age;
13 this.salary = salary;
14 }
15
16 public String getStaffId() {
17 return staffId;
18 }
19
20 public void setStaffId(String staffId) {
21 this.staffId = staffId;
22 }
23
24 public String getName() {
25 return name;
26 }
27
28 public void setName(String name) {
29 this.name = name;
30 }
31
32 public int getAge() {
33 return age;
34 }
35
36 public void setAge(int age) {
37 this.age = age;
38 }
39
40 public float getSalary() {
41 return salary;
42 }
43
44 public void setSalary(float salary) {
45 this.salary = salary;
46 }
47
48 @Override
49 public String toString() {
50 return "StaffInfo{" +
51 "staffId='" + staffId + '\'' +
52 ", name='" + name + '\'' +
53 ", age=" + age +
54 ", salary=" + salary +
55 '}';
56 }
57 }

StaffInfoDataModel.java

 1 package com.song.mvpdemo.staffinfo.model;
2
3 import android.os.Handler;
4
5 import com.song.mvpdemo.mvpbase.model.BaseModel;
6 import com.song.mvpdemo.mvpbase.model.ModelCallback;
7
8 public class StaffInfoDataModel extends BaseModel<StaffInfo> {
9
10 @Override
11 public void execute(ModelCallback<StaffInfo> modelCallback) {
12 new Handler().postDelayed(new Runnable() {
13 @Override
14 public void run() {
15 switch (mParams[0]) {
16 case ""://输入的staffid为空,则显示失败
17 modelCallback.onFailOrError();
18 break;
19 default:
20 StaffInfo staffInfo = new StaffInfo(mParams[0], "张三", 20, 20000);
21 modelCallback.onSuccess(staffInfo);
22 break;
23 }
24 modelCallback.onCompleted();
25 }
26 }, 5000);
27 }
28 }

StaffInfoPresenter.java

 1 package com.song.mvpdemo.staffinfo.presenter;
2
3 import com.song.mvpdemo.mvpbase.presenter.BasePresenter;
4 import com.song.mvpdemo.mvpbase.model.DataModel;
5 import com.song.mvpdemo.mvpbase.model.ModelCallback;
6 import com.song.mvpdemo.staffinfo.model.StaffInfo;
7 import com.song.mvpdemo.staffinfo.model.StaffInfoDataModel;
8 import com.song.mvpdemo.staffinfo.view.IStaffInfoView;
9
10 public class StaffInfoPresenter extends BasePresenter<IStaffInfoView> {
11
12 public void queryStaffInfo(String param) {
13 getView().showLoading();
14
15 DataModel.createModel(StaffInfoDataModel.class)
16 .params(param)
17 .execute(new ModelCallback<StaffInfo>() {
18 @Override
19 public void onSuccess(StaffInfo result) {
20 if (isViewAttached()) {
21 getView().showStaffInfo(result);
22 }
23 }
24
25 @Override
26 public void onFailOrError() {
27 if (isViewAttached()) {
28 getView().showFailOrError("fail");
29 }
30 }
31
32 @Override
33 public void onCompleted() {
34 if (isViewAttached()) {
35 getView().hideLoading();
36 }
37 }
38 });
39 }
40 }

IStaffInfoView.java

 1 package com.song.mvpdemo.staffinfo.view;
2
3 import com.song.mvpdemo.mvpbase.view.IBaseView;
4 import com.song.mvpdemo.staffinfo.model.StaffInfo;
5
6 public interface IStaffInfoView extends IBaseView {
7 /**
8 * 具体业务特有的方法,无法做为通用的方法提取出来
9 */
10 String getStaffId();
11
12 void showStaffInfo(StaffInfo staffInfo);
13
14 void clearStaffId();
15 }

StaffInfoActivity.java

 1 package com.song.mvpdemo.staffinfo.view;
2
3 import android.os.Bundle;
4 import android.view.View;
5 import android.widget.EditText;
6 import android.widget.TextView;
7
8 import com.song.mvpdemo.mvpbase.view.BaseActivity;
9 import com.song.mvpdemo.mvpbase.presenter.BasePresenter;
10 import com.song.mvpdemo.R;
11 import com.song.mvpdemo.staffinfo.presenter.StaffInfoPresenter;
12 import com.song.mvpdemo.staffinfo.model.StaffInfo;
13
14 public class StaffInfoActivity extends BaseActivity implements IStaffInfoView {
15 private TextView mStaffInfoTv;
16 private EditText mStaffIdEt;
17 private StaffInfoPresenter mStaffInfoPresenter;
18
19 @Override
20 protected void onCreate(Bundle savedInstanceState) {
21 super.onCreate(savedInstanceState);
22 setContentView(R.layout.activity_staffinfo);
23 initView();
24 }
25
26 private void initView() {
27 mStaffInfoTv = findViewById(R.id.tv_result);
28 mStaffIdEt = findViewById(R.id.staffId_et);
29 findViewById(R.id.btn_submit).setOnClickListener(new View.OnClickListener() {
30 @Override
31 public void onClick(View view) {
32 mStaffInfoPresenter.queryStaffInfo(getStaffId());
33 }
34 });
35
36 findViewById(R.id.btn_clear).setOnClickListener(new View.OnClickListener() {
37 @Override
38 public void onClick(View view) {
39 clearStaffId();
40 }
41 });
42 }
43
44
45 @Override
46 protected void initPresenter() {
47 mStaffInfoPresenter = new StaffInfoPresenter();
48 }
49
50 @Override
51 protected BasePresenter getPresenter() {
52 return mStaffInfoPresenter;
53 }
54
55 @Override
56 public void showFailOrError(String msg) {
57 mStaffInfoTv.setText(msg);
58 }
59
60 @Override
61 public String getStaffId() {
62 return mStaffIdEt.getText().toString();
63 }
64
65 @Override
66 public void showStaffInfo(StaffInfo staffInfo) {
67 mStaffInfoTv.setText(staffInfo.toString());
68 }
69
70 @Override
71 public void clearStaffId() {
72 mStaffIdEt.setText("");
73 }
74 }

activity_staffinfo.xml

 1 <?xml version="1.0" encoding="utf-8"?>
2 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 tools:context=".staffinfo.view.StaffInfoActivity">
8
9 <TextView
10 android:id="@+id/tv_result"
11 android:layout_width="wrap_content"
12 android:layout_height="wrap_content"
13 android:layout_marginTop="50dp"
14 android:text=""
15 app:layout_constraintLeft_toLeftOf="parent"
16 app:layout_constraintRight_toRightOf="parent"
17 app:layout_constraintTop_toTopOf="parent" />
18
19 <EditText
20 android:id="@+id/staffId_et"
21 android:layout_width="200dp"
22 android:layout_height="wrap_content"
23 android:layout_marginTop="20dp"
24 android:hint="input staff id"
25 app:layout_constraintLeft_toLeftOf="parent"
26 app:layout_constraintRight_toRightOf="parent"
27 app:layout_constraintTop_toBottomOf="@id/tv_result" />
28
29
30 <Button
31 android:id="@+id/btn_submit"
32 android:layout_width="200dp"
33 android:layout_height="wrap_content"
34 android:layout_marginTop="50dp"
35 android:text="submit"
36 app:layout_constraintLeft_toLeftOf="parent"
37 app:layout_constraintRight_toRightOf="parent"
38 app:layout_constraintTop_toBottomOf="@id/staffId_et" />
39
40 <Button
41 android:id="@+id/btn_clear"
42 android:layout_width="200dp"
43 android:layout_height="wrap_content"
44 android:text="clear"
45 app:layout_constraintLeft_toLeftOf="parent"
46 app:layout_constraintRight_toRightOf="parent"
47 app:layout_constraintTop_toBottomOf="@id/btn_submit" />
48
49 </androidx.constraintlayout.widget.ConstraintLayout>

参考:

Android MVP升级路(一)乞丐版的自我救赎

Android MVP升级路(二)轻项目标配之时尚版

Android MVP升级路(三)随心所欲的旗舰版

浅谈 MVP in Android

 
 
 

【架构】整理了一份通用的MVP框架示例代码的更多相关文章

  1. Android MVP框架 详细代码

    android mvp的好处,网上一搜一大堆,相对于一开始普通的在activity中处理所有的不管是网络请求还是页面渲染,最大的好处是简洁了,废话不多说,看代码 这里网络请求使用了两种,一种是自己封装 ...

  2. 根据网站所做的SEO优化整理的一份文档

    今日给合作公司讲解本公司网站SEO优化整理的一份简单文档 架构 ########################################## 1.尽量避免Javascript和flash导航. ...

  3. 整理收藏一份PHP高级工程师的笔试题

    整理了一份PHP高级工程师的笔试题,问题很全面.嗯,基本上这些题都答得不错,那么你应该可以胜任大部分互联网企业的PHP职位了.下面直接上题. 1. 基本知识点 HTTP协议中几个状态码的含义:503, ...

  4. 整理收藏一份PHP高级工程师的笔试…

    注:本文转自 http://www.icultivator.com/p/5535.html 注:本文转自 http://www.yiichina.com/tutorial/57 整理了一份PHP高级工 ...

  5. 我自己总结的C#开发命名规范整理了一份

    我自己总结的C#开发命名规范整理了一份 标签: 开发规范文档标准语言 2014-06-27 22:58 3165人阅读 评论(1) 收藏 举报  分类: C#(39)  版权声明:本文为博主原创文章, ...

  6. [转] 整理了一份React-Native学习指南

    自己在学习React-Native过程中整理的一份学习指南,包含 教程.开源app和资源网站等,还在不断更新中.欢迎pull requests! React-Native学习指南 本指南汇集React ...

  7. 整理了一份React-Native学习指南

    原文:  http://www.w3ctech.com/topic/909 自己在学习React-Native过程中整理的一份学习指南,包含 教程.开源app和资源网站等,还在不断更新中.欢迎pull ...

  8. 我整理的一份来自于线上的Nginx配置(Nginx.conf),希望对学习Nginx的有帮助

    我整理了一份Nginx的配置文件说明,是真正经历过正式线上考验过.如果有优化的地方,也请朋友们指点一二,整理出一份比较全而实用的配置. 主要包含配置:负载均衡配置,页面重定向,转发,HTTPS和HTT ...

  9. 肝了很久,冰河整理出这份4万字的SpringCloud与SpringCloudAlibaba学习笔记!!

    写在前面 不少小伙伴让我整理下有关SpringCloud和SpringCloudAlibaba的知识点,经过3天的收集和整理,冰河整理出这份4万字的SpringCloud与SpringCloudAli ...

  10. 移动架构之MVP框架

    MVP是在开发中常用的框架,要了解其原理,先要从了解MVC开始,这里就对MVP框架做一个简单的介绍 MVC MVC为Model,View与Controllor的缩写 Model:业务逻辑和实体模型 V ...

随机推荐

  1. 数据库MySQL-安装、卸载、配置、登录、退出

    一.下载 下载链接:MySQL :: Download MySQL Community Server (Archived Versions) 二.安装(解压)  三.配置 1.添加环境变量 我的电脑- ...

  2. Python—开发工具 PyCharm 使用

    一.创建新工程: 第一个工程创建完毕!

  3. Libevent学习-源码下载和交叉编译,示例代码运行

    1. 官网 2. 交叉编译 我的当前环境 mips平台交叉编译说明 先解压下载后的libevent源码压缩包然后cd进入解压后的文件夹libevent-2.1.11-stable: <1. ./ ...

  4. 「模拟赛」A 层多校联训 4(卖品:CTH)

    双倒一啦! 感觉这次最大的错误就是没看 T2.(本质原因还是时间浪费的太多了) 赛时记录在闲话啦 accoder 多校比赛链接 02 表示法 唐诗题!考高精的人都\(**\),输出深度优先搜索解决.高 ...

  5. 活动预告 | 中国数据库联盟(ACDU)中国行第二站定档杭州,邀您探讨数据库技术与实践!

    数据库技术一直是信息时代中不可或缺的核心组成部分,随着信息量的爆炸式增长和数据的多样化,其重要性愈发凸显.作为中国数据库联盟(ACDU)的品牌活动之一,[ACDU 中国行]在线下汇集数据库领域的行业知 ...

  6. excel导出功能的实现流程说⼀下?

    导出的话,我们因为到处的数据量不⼤,所以直接采取的时候前端主导的⽅案,参考的现成⽅案实现的 导出 ⼤概得流程就是 1. 调⽤后端接⼝得到要导出的数据 2. 把数据简单处理⼀下转化成导出插件需要的格式 ...

  7. 容器化部署nacos 1.4.6报错caused: The specified key byte array is 0 bits which is not secure enough for any JWT

    nacos2.0+ 与nacos 1.x区别 nacos在2.0+版本开始使用grpc与客户端通信,并且通过非8848端口通信 主要是有两个端口 端口 与主端口的偏移量 描述 9848 1000 客户 ...

  8. 小A的组合数

    小A的组合数 题目描述 \(C_n^m\)表示组合,组合公式为:\(C_n^m=\frac{n!}{m!\times (n-m)!}\),请你求出\(C_n^m\)的因子个数\(tot\),由于大难会 ...

  9. 防火墙NAT配置与DHCP下发

    该实验如果有做的不足的地方请见谅 实验目标: 按要求划分区域,公司内部办公区为trust,服务器区为dmz,外部网络为untrust. PC1和PC2为公司内部办公区,需要从防火墙中的DHCP服务获取 ...

  10. mini-web框架 添加log日志

    阅读目录: 1.mini-web框架-路由支持正则 2.mini-web框架-mysql-增 3.mini-web框架-mysql-删 4.mini-web框架-mysql-改 5.mini-web框 ...