最近回顾了一下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>
参考:
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来
文章目录git常用命令(简介,详细参数往下看)Git提交代码步骤gitpullgitstatusgitaddgitcommitgitpushgit代码冲突合并问题方法一:放弃本地代码方法二:合并代码常用命令以及详细参数gitadd将文件添加到仓库:gitdiff比较文件异同gitlog查看历史记录gitreset代码回滚版本库相关操作远程仓库相关操作分支相关操作创建分支查看分支:gitbranch合并分支:gitmerge删除分支:gitbranch-ddev查看分支合并图:gitlog–graph–pretty=oneline–abbrev-commit撤消某次提交git用户名密码相关配置g
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图