Android(安卓)MVP应用
Android 谷歌官方MVP模式解读
一. 目录
-
-
- Android 谷歌官方MVP模式解读
- 一. 目录
- 二.MVP的含义
- 1.MVC模式
- 2.MVP
- 三.原来的写法
- 1. 定义View接口,里面供提供p层抽象方法
- 2. Activity或者Fragemt实现View接口
- 3. Model层的接口定义,里面供提供p层抽象方法
- 4. Model层实现
- 5.Presenter代码及实现
- 6.Presenter与View的通信
- 7.Presenter与View的通信
- 四.借鉴谷歌官方的写法
- 1.定义基础的P和V接口
- 2.定义Contract接口
- 3.定义协议类EducationDataSource
- 4.V的实现类 ComputersGradeActivity
- 5. P的实现类 ComputersGradePresenter
- 6. M的实现类
-
二.MVP的含义
MVP在我上一个写关于地图的项目时候,在项目开始前也进行过学习,也在项目中也进行了应用。在今年暑假开始写西邮助手的时候,和小伙伴也是计划用MVP打框架。重新查阅资料发现,谷歌官方提供了一个MVP模式的Demo。所以对它进行了学习阅读,同时决定写一篇博客进行记录。
1.MVC模式
MVC即Model-View-Controller.即M:逻辑模型,V:视图模型,C:控制器
MVC模式下,系统框架的类库被划分为3种:模型(Model)、视图(View)、控制器(Controller)。模型对象负责建立数据结构和相应的行为操作处理。视图对象负责在屏幕上渲染出相应的图形信息展示给用户看。控制器对象负责截获用户的按键和屏幕触摸等事件,协调Model对象和View对象。
用户与视图交互,视图接收并反馈用户动作,视图把用户的请求传给相应的控制器,由控制器决定调用哪个模型,然后由模型调用相应的业务逻辑对用户请求进行加工处理,最后由模型对视图进行选择。即如下图所示
Android中的MVC
Android世界中也经常运用到MVC模式。
Activity对应视图界面也就是View层。
数据库文件,Sharedprefrence,内存缓冲,磁盘缓冲等数据内容对应Model层。
而Controller控制层基本上也由Activity层面来进行。
MVC中的不足
是的MVC是挺好的,但是它也有它的缺点,特别是针对Androi开发。
因为Android的特殊性,使得Activity对应了MVC中的V和C,同时担任两个角色,就有了类似“既当爹又当妈”的感觉,这显然就不符合软件设计原则的“单一职责”原则。但现实中是很多的APP代码中有这么的处境,特别是Androi原生的很多系统APK,某些Activity动则几千行代码。 所以越来越多的人选择MVP模式。
2.MVP
MVP即:Model-View-Presenter,MVP是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
MVP和MVC最大的区别就是 moder不能直接调用View,他们之间的通信是通过Presenter来进行的,所有的交互都发生在Presenter内部。两这区别如下:
在Android中应用到MVP,就是可以是V和P之间进行相互通信,P和M之间进行相互通信。简单举个下拉刷新的例子。
下拉刷新: V(刷新)–>P(通知M进行网络请求)–>M(进行网络请求);M(请求完毕)—>P(通知V加载更多)—>V(加载数据)。
三.原来的写法
我原来的写法是参考这一篇博客的
Android中MVP模式讲解及实践
1. 定义View接口,里面供提供p层抽象方法
public interface IWetherView { public void onInfoUpdate(String info); public void showWaitingDialog(); public void dissmissWaitingDialog();}
2. Activity或者Fragemt实现View接口
public class MainActivity extends AppCompatActivity implements IWetherView{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onInfoUpdate(String info) { } @Override public void showWaitingDialog() { } @Override public void dissmissWaitingDialog() { }}
3. Model层的接口定义,里面供提供p层抽象方法
public interface IWetherModel { //提供数据 public String getInfo(); //存储数据 public void setInfo(String info);}
4. Model层实现
public class IWetherImpl implements IWetherModel { @Override public String getInfo() { return null; } @Override public void setInfo(String info) { }}
5.Presenter代码及实现
Presenter中实现对V和M的调用,所以在P中要持有V和M的对象
public interface IWetherModel { IWetherModel mModel; IWetherView mView; //供View层调用,用来请求天气数据 public void requestWetherInfo(){ }}
6.Presenter与View的通信
View—–>Presenter
public class MainActivity extends AppCompatActivity implements IWetherView{ ...... WetherPresenter mPresenter =WetherPresenter(this) ; ......}
Presenter—>View
public class WetherPresenter { IWetherModel mModel; IWetherView mView; ...... public WetherPresenter(IWetherView mView) { this.mView = mView; } ......}
7.Presenter与View的通信
Presenter—->Model
public class WetherPresenter { IWetherModel mModel; IWetherView mView; ...... public WetherPresenter(IWetherView mView) { this.mView = mView; mModel = new IWetherModelImpl(this); } ......}
Model—->Presenter
public class IWetherImpl implements IWetherModel { WetherPresenter mPresenter; public IWetherImpl(WetherPresenter presenter) { this.mPresenter = presenter; } @Override public String getInfo() { return null; } @Override public void setInfo(String info) { }}
完成这些后,就可以进行V–>P–>M–>P–>V 的过程
四.借鉴谷歌官方的写法
我借鉴的是谷歌MVP-Rxjava的写法,大部分和原写法相同,在某些地方进行了改进,谷歌官方的写法中,Fragment作为V,Activity只是作为将两者进行绑定的渠道,我在项目中,将Activity作为V。
谷歌官方MVP + Rxjava的讲解:Google官方MVP+Rxjava项目详解
在我的项目中的应用:以四六级查询为例
1.定义基础的P和V接口
public interface BasePresenter { //订阅 void subscribe(); //取消订阅 void unSubscribe();}
public interface BaseView { void setPresenter(T presenter);}
2.定义Contract接口
在Contract接口中设置该模块 V和P提供的接口
public interface ComputersGradeContract { interface View extends BaseView<Presenter> { void cgGetTimes(CgTimes cgTimes); //展示时间 void cgShowValidateCode(Bitmap bitmap); //展示验证码 void cgShowGrade(CgQuery cgQuery); //展示成绩 void cgFailure(String str); //请求失败 } interface Presenter extends BasePresenter { void cgSetValidateCode(); //请求验证码 void cgSetGrade(CgDemandDate cgDemandDate); //请求成绩 }}
3.定义协议类EducationDataSource
这个就是定义M的接口,里面写了M需要实现的接口。
public interface EducationDataSource { //计算机等级考试 Observable cgTimes(); Observable cgValidateCode(); Observable cgGrade(CgDemandDate cgDemandDate);}
4.V的实现类 ComputersGradeActivity
public class ComputersGradeActivity extends BaseActivity implements ComputersGradeContract.View { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_computers_grade); initView(); clickJudge(); //创建一个P实例 //参数1 M的实例 //参数2 V的实例 new ComputersGradePresenter(Injection.provideTasksRepository(getApplicationContext()), this); } ... @Override public void onResume() { super.onResume(); mPresenter.subscribe(); //P进行订阅 } @Override public void onPause() { super.onPause(); mPresenter.unSubscribe();//P取消订阅 } @Override public void setPresenter(@NonNull ComputersGradeContract.Presenter presenter) { mPresenter = presenter; // v-->P } @Override //展示时间 提供给P调用的接口 public void cgGetTimes(CgTimes cgTimes) { mDateSet = cgTimes.data; OptionsPickerView lessonDatePickerView = getDateOptionPickerView(cgTimes); mLlDate.setOnClickListener(view -> lessonDatePickerView.show()); } @Override //展示验证码 提供给P调用的接口 public void cgShowValidateCode(Bitmap bitmap) { mIvCode.setImageBitmap(bitmap); } @Override//展示成绩 提供给P调用的接口 public void cgShowGrade(CgQuery cgQuery) { if(cgQuery.status == 500){ Toast.makeText(Utils.getContext(), "信息有误", Toast.LENGTH_SHORT).show(); }else if(cgQuery.data == null){ Toast.makeText(Utils.getContext(), "验证码错误", Toast.LENGTH_SHORT).show(); mPresenter.cgSetValidateCode(); }else { mAnimatorSet.start(); mTvGrade.setText(cgQuery.data.status); mTvCredential.setText(cgQuery.data.zkzh); } } @Override //请求失败 public void cgFailure(String str) { Toast.makeText(Utils.getContext(), str, Toast.LENGTH_SHORT).show(); }}
Injection类
public class Injection { public static EducationRepository provideTasksRepository(@NonNull Context context) { return EducationRepository.getInstance( EducationRemoteDataSource.getInstance(), EducationLocalDataSource.getInstance(context)); }}
5. P的实现类 ComputersGradePresenter
public class ComputersGradePresenter implements ComputersGradeContract.Presenter { @NonNull private final ComputersGradeContract.View mView; //V的实例 @NonNull private final EducationRepository mEducationRepository; //M的实例 @NonNull private CompositeDisposable mCompositeDisposable; private static final String TAG = "ComputersGradePresenter"; public ComputersGradePresenter(@Nullable EducationRepository educationRepository, @NonNull ComputersGradeContract.View view) { //p和V绑定 mView = view; //p和M绑定 mEducationRepository = educationRepository; //V和p绑定 mView.setPresenter(this); mCompositeDisposable = new CompositeDisposable(); } //订阅 @Override public void subscribe() { cgSetTimes(); //请求时间 cgSetValidateCode(); //请求验证码 } //取消订阅 @Override public void unSubscribe() { mCompositeDisposable.clear(); } //获取时间列表 public void cgSetTimes() { //使用RXjava对M发送回的事件进行处理 mCompositeDisposable.add(mEducationRepository .cgTimes() //调用M的cgTimes方法 .subscribeOn(Schedulers.io()) //提供Scheduler用于Rxjava线程调度 .observeOn(AndroidSchedulers.mainThread()) .subscribe( // onNext cgTimes-> { if (cgTimes == null) { mView.cgFailure("网络请求失败"); //调用页面出错 } else { mView.cgGetTimes(cgTimes); } }, // onError throwable -> mView.cgFailure("网络请求失败")));//调用页面出错 } @Override //获取验证码 public void cgSetValidateCode() { mCompositeDisposable.add(mEducationRepository .cgValidateCode() .subscribeOn(Schedulers.io()) //提供Scheduler用于Rxjava线程调度 .observeOn(AndroidSchedulers.mainThread()) .subscribe( // onNext bitmap-> { if (bitmap == null) { mView.cgFailure("网络请求失败1"); //调用页面出错 } else { mView.cgShowValidateCode(bitmap); } }, // onError throwable -> mView.cgFailure("网络请求失败2"))); //调用页面出错 } @Override //获取成绩 public void cgSetGrade(CgDemandDate cgDemandDate) { mCompositeDisposable.add(mEducationRepository .cgGrade(cgDemandDate) .subscribeOn(Schedulers.io()) //提供Scheduler用于Rxjava线程调度 .observeOn(AndroidSchedulers.mainThread()) .subscribe( // onNext cgQuery-> { if (cgQuery == null) { mView.cgFailure("信息有误"); //调用页面出错 } else { mView.cgShowGrade(cgQuery); } }, // onError throwable -> mView.cgFailure("信息有误"))); //调用页面出错 }}
6. M的实现类
M的实现类有三个:EducationRepository,EducationRemoteDataSource代表网络数据,EducationLocalDataSource 代表本地数据,EducationRepository根据需求决定调用哪一个DataSource。
EducationRepository
ublic class EducationRepository implements EducationDataSource { @NonNull private final EducationDataSource mTasksRemoteDataSource; @NonNull private final EducationDataSource mTasksLocalDataSource; //单例模式 private EducationRepository(@NonNull EducationDataSource tasksRemoteDataSource, @NonNull EducationDataSource tasksLocalDataSource) { mTasksRemoteDataSource = tasksRemoteDataSource; mTasksLocalDataSource = tasksLocalDataSource; } @Nullable private static EducationRepository INSTANCE = null; public static EducationRepository getInstance(@NonNull EducationDataSource tasksRemoteDataSource, @NonNull EducationDataSource tasksLocalDataSource) { if (INSTANCE == null) { INSTANCE = new EducationRepository(tasksRemoteDataSource, tasksLocalDataSource); } return INSTANCE; } @Override public Observable cgTimes() { return mTasksRemoteDataSource.cgTimes(); } @Override public Observable cgValidateCode() { return mTasksRemoteDataSource.cgValidateCode(); } @Override public Observable cgGrade(CgDemandDate cgDemandDate) { return mTasksRemoteDataSource. cgGrade(cgDemandDate); }}
EducationRemoteDataSource类
public class EducationRemoteDataSource implements EducationDataSource { private static EducationRemoteDataSource INSTANCE; //单例 // Prevent direct instantiation. private EducationRemoteDataSource() { } public static EducationRemoteDataSource getInstance() { if (INSTANCE == null) { INSTANCE = new EducationRemoteDataSource(); } return INSTANCE; } @Override public Observable cgTimes() { return RetrofitFactory.INSTANCE.create(EducationApi.class) .cgGetTimes() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .flatMap(new Function>() {//将请求的结果封装成一个新的事件 @Override public ObservableSource apply(CgTimes cgTimes) throws Exception { return Observable.create(e -> e.onNext(cgTimes)); } }); } @Override public Observable cgValidateCode() { return RetrofitFactory.INSTANCE.create(EducationApi.class) .cgGetCode() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .flatMap(new Function>() { //将请求的结果封装成一个新的事件 @Override public ObservableSource apply(ResponseBody responseBody) throws Exception { Bitmap bitmap = BitmapFactory.decodeStream(responseBody.byteStream()); return Observable.create(e -> e.onNext(bitmap)); } }); } @Override public Observable cgGrade(CgDemandDate cgDemandDate) { return RetrofitFactory.INSTANCE.create(EducationApi.class) .cgGetQuery(cgDemandDate.getDate(),cgDemandDate.getType(),cgDemandDate.getNum(),cgDemandDate.getName(),cgDemandDate.getCode()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .flatMap(new Function>() { @Override public ObservableSource apply(CgQuery cgGuery) throws Exception { return Observable.create(e -> e.onNext(cgGuery)); } }); }
在我的项目中,这个模块没有用的EducationLocalDataSource,所以基本它对应的方法返回的都是空值。
更多相关文章
- android2.3 api demo 学习系列(1)--apidemo主列表的实现
- Android(安卓)显示系统键盘搜索按键,实现搜索功能
- 写给初学者Android(安卓)AIDL必看内容
- Android(安卓)使用Parcelable传递对象
- 【Android(安卓)Demo】通过WebService获取今日天气情况
- Android(安卓)下使用 JSON 实现 HTTP 请求,外加几个示例!
- android Activity实现从底部弹出或滑出选择菜单或窗口
- DIY新浪微博Android手机客户端(一)(二)(三)完
- 浅谈Java中Collections.sort对List排序的两种方法