【架构】整理了一份通用的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<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>
参考: