【架构】整理了一份通用的MVP框架示例代码


       最近回顾了一下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 {
 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 modelCallback);
26 
27     /**
28      * 执行Get网络请求,此类看需求由自己选择写与不写
29      */
30     public void requestGetApi(String url, ModelCallback modelCallback) {
31         //这里写具体的网络请求
32     }
33 
34     //执行Post网络请求,此类看需求由自己选择写与不写
35     public void requestPostApi(String url, Map params, ModelCallback modelCallback) {
36         //这里写具体的网络请求
37     }
38 }

ModelCallback.java

 1 package com.song.mvpdemo.mvpbase.model;
 2 
 3 /**
 4  * Presenter层调用Model层后数据回调
 5  */
 6 public interface ModelCallback {
 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 BasePresenterextends 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 {
 9 
10     @Override
11     public void execute(ModelCallback 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 {
11 
12     public void queryStaffInfo(String param) {
13         getView().showLoading();
14 
15         DataModel.createModel(StaffInfoDataModel.class)
16                 .params(param)
17                 .execute(new ModelCallback() {
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