1、概述

对于MVP(Model View Presenter)大多数做开发的人都能说出一二,或者看到网上的对mvp的解释,对其意都有大概的了解,但让你真正写一套mvp框架,是不是发现无从下手?

曾几何本人接触MVP+Retrofit2.0+Rxjava也有同样的疑惑,固知道问题所在,网上关于MVP方面文章太多,千篇一律,看起来比较费力,其实只要看懂一篇文章就够了,为此这篇文章本人写的比较详细,如果无从下手,可以看看这篇文章,本人趁工作之余,花了一定时间写了一篇,让你快速学会搭建一个自己MVP+Retrofit2.0+Rxjava框架,通用以后的项目中。

1.1、框架好处:

MVP框架的好处就是解耦,让代码分离,便于重构、测试,避免activity业务繁重,让代码看起来干净利落。

2、理解MVP的构成

View :对应于Activity,负责View的绘制以及与用户交互

Model :就是数据源,可以理解为数据相关的模块,它不仅包含实体类的定义,还包含一切跟数据有关的操作比如数据库、网络(获取、解析、存储),项目最常见的网络请求数据操作就放在,mode层里面

Presenter :负责完成View于Model间的交互,也就是通过presenter将mode里面的网络获取到的数据交给View(activity、或者Fragment处理),p层是交通运纽中心,P说白了就是全是java代码。

3、mvp框架交互方式

3.1、mvp最关键技术就在于接口的运用,将接口回调发挥的淋漓精致,同时也将activity大多数代码分离、解耦出来,让代码更清晰,更工整;

3.2、上面说到Presenter完成View于Model间的交互通过接口,p层涉及两个重要回调:

3.3、在P层中,使用mode对象调用接口,mode具体实现网络操作方法

3.4、在P层中,使用view对象调用接口传递数据,在activity实现接口方法,更新UI。

4、是时候打造自己的万能MVP框架了

xing.jpg

4.1、定义最基层的IView 接口用于P和v的交互;IPresenter实现该接口,P层继承IPresenter接口,使得该框架面对接口;IModel 接口是最基层用P和M交互接口

/**

*Created by ljp on 2018/9/20.

*

* 最基层负责presenter和activity交互接口

* 这里是是一些更新Activity也就是更新view的接口,最基层,以便不同view扩展

*/

public interface IView {

void showDialog();

void dissDialog();

}

/**

*这里是最基层的mode,因为不同的view有不同的mode,但有功能的网络操作,便可以在mode里写接

*口,便于扩展

*/

public interface IModel {

}

/**

*最基层的Present接口,使得以后的具体Present都都具备这个接口属性,具备IPresenter这个接口属性,

*便可以调用IPresenter接口方法

*/

public interface IPresenter {

void attach(VIEW view);

void detach();

}

4.2、这里是所有实现基层IModel 、IView 、IPresenter接口,基层一切为了扩展,具体作用标注

/**

* Created by ljp on 2018/9/20.

*

* model和view接口基础接口管理

*/

public interface StudentMainContract {

/**

* mode和present交互接口,具体网络操作

*/

interface Model extends IModel {

/**

* 学段选择数据请求接口

*/

void doHttpStudentSection(NetWorkCallback> netWorkCallback);

}

/**

* 负责更新ui接口

*/

interface View extends IView {

/**

* 更新学段ui接口

*/

void initStudentSelect(List beanList);

}

/**

* view和present交互接口,view中调用,present实现

*/

interface Presenter extends IPresenter {

/**

* 获取学段网络接口

*/

void getHttpStudentSectionData();

}

}

4.3、打造万能P层,基本套路形,该P层继承了IPresenter接口,实现attach和detach方法,attach方法含义如下

/**

* Created by ljp on 2018/9/20.

*

* 基层present

*/

public abstract class BasePresenter implements IPresenter {

private WeakReference mView;

private MODEL mModel;

/**

* @param view 对的activity上下文对象,具体activtiy(view)实现了不同的接口,进行回调对应接口方法时候用到(接口子类对象类对象调用接口方法),

* activty退出了,某个接口进网络操作,存在对当前上下午引用,存在内存泄漏,使用WeakReference解决。

*/

public void attach(VIEW view) {

mView = new WeakReference<>(view);

mModel = createModel();

}

@CallSuper

public void detach() {

if (mView != null) {

mView.clear();

mView = null;

}

}

protected VIEW getView() {

if (mView != null) {

return mView.get();

}

return null;

}

protected MODEL getModel() {

return mModel;

}

protected abstract MODEL createModel();

}

4.4、这是基层BaseMvpActivity,泛型需要传入泛型参数IView型和IPresenter型(这里说明具体的present都实现了基层IPresenter接口),以下注意理解:

4.4. 1、getIView()在具体view里面实现了,这里是StudentMainActivity 实现,getView()就是对应的activtiy对象;

4.4.2、StudentMainActivity 继承了StudentMainContract.View接口、View继承IView接口,

4.4.3、 attach 参数就是IView类型,StudentMainActivity 是IView接口子类;

4.4.4、具体present类StudentMainPresenterImpl 就继承了StudentMainContract.Presenter接口,Presenter继承IPresenter,所有StudentMainPresenterImpl是IPresenter接口子类,便可以调用attach。

public abstract class BaseMvpActivity> extends Activity {

private PRESENTER mPresenter;

private LekeProgressDialog mLekeProgressDialog;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mPresenter = createPresenter();

mPresenter.attach(getIView());

mLekeProgressDialog = new LekeProgressDialog(this);

}

public void showLekeDialog() {

if (mLekeProgressDialog == null) {

mLekeProgressDialog = new LekeProgressDialog(this);

}

mLekeProgressDialog.show();

}

public void dissLekeMissDialog() {

if (mLekeProgressDialog != null) {

mLekeProgressDialog.dismiss();

}

mLekeProgressDialog = null;

}

@Override

protected void onDestroy() {

super.onDestroy();

if (mPresenter != null) {

mPresenter.detach();

}

dissLekeMissDialog();

}

protected PRESENTER getPresenter() {

return mPresenter;

}

protected abstract PRESENTER createPresenter();

protected abstract VIEW getIView();

}

4.5、具体使用,都是接口类型;

之前使用IPresenter接口目的是让具体的StudentMainPresenterImpl 接口化,IPresenter接口目的仅仅就是让对应StudentMainActivity (View)调用到StudentMainPresenterImpl 里面方法(Presenter);

/**

* Created by ljp on 2018/9/20.

*

* 主页

*/

public class StudentMainActivity extends BaseMvpActivity

StudentMainContract.Presenter> implements StudentMainContract.View {

private TextView mTextView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Button button = findViewById(R.id.btn);

mTextView = findViewById(R.id.tv);

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

//TODO 开始学生网络请求

getPresenter().getHttpStudentSectionData();

}

});

}

@Override

protected StudentMainContract.Presenter createPresenter() {

return new StudentMainPresenterImpl();

}

@Override

protected StudentMainContract.View getIView() {

return this;

}

/**

* 更新学段ui接口

*

* @param beanList

*/

@Override

public void initStudentSelect(List beanList) {

//TODO 更新UI操作

}

@Override

public void dissDialog() {

dissLekeMissDialog();

mTextView.setText("网络请求加载完毕");

}

@Override

public void showDialog() {

showLekeDialog();

mTextView.setText("网络请求加载完毕");

}

}

4.6.1、具体StudentMainPresenterImpl 的编写方式,继承StudentMainContract.Presenter接口,实现StudentMainContract.Presenter接口方法,activtiy需要做什么操作,这里是请求学段,在对应activity中调用getHttpStudentSectionData()请求学段方法;

4.6.2、 getView()上面说了返回的是activity对象,该acitivty继承view接口,view接口负责Present和activity中uI更新的,所以 getView().showDialog是打开加载匡加载UI;

4.6.3、 getModel().doHttpStudentSection是调用mode接口方法,具体网络请求操作实现在mode里面;

4.6.4、接口成功回调接口个人差异不同,有不同编写方式。

/**

* Created by ljp on 2018/9/20.

*

* 具体实现presenter

*/

public class StudentMainPresenterImpl extends BasePresenter

StudentMainContract.Model> implements StudentMainContract.Presenter {

/**

* 获取学段网络接口

*/

@Override

public void getHttpStudentSectionData() {

getView().showDialog();

getModel().doHttpStudentSection( new NetWorkCallback>() {

@Override

public void onSucceed(List studentBeanResponses) {

if (getView() != null) {

getView().dissDialog();

getView().initStudentSelect(studentBeanResponses);

}

}

@Override

public void onFailed(Throwable error) {

if (getView() != null) {

getView().dissDialog();

}

}

});

}

@Override

protected StudentMainContract.Model createModel() {

return new StudentMainModelImpl((Context) getView());

}

}

4.7、这里就是具体的mode,具体网络操作在这里实现,请求完成后,回调到Present中,在Present中拿到数据,使用View接口回调更新Activity.

/**

* Created by ljp on 2018/9/20.

*

* 具体实现model

*/

public class StudentMainModelImpl implements StudentMainContract.Model {

protected RxHttpUtils rxHttpUtils;

public StudentMainModelImpl(Context context) {

rxHttpUtils = new RxHttpUtils(context);

}

/**

* 学段选择数据请求接口

*

* @param netWorkCallback

*/

@Override

public void doHttpStudentSection(final NetWorkCallback> netWorkCallback) {

//TODO 这里的接口地址是本人随便写的,所以会请求失败这里用延迟表示网络加赞

HttpRx.normal(rxHttpUtils.getSearchStudnt())

.subscribe(new LekeObserver>() {

@Override

public void onSucced(List responses) {

if (netWorkCallback != null) {

netWorkCallback.onSucceed(responses);

}

}

@Override

public void onFailed(final Throwable error) {

if (netWorkCallback != null) {

new Handler().postDelayed(new Runnable(){

public void run() {

netWorkCallback.onFailed(error);

}

}, 2000);

}

}

});

}}

好了,mvp套路基本就是这样,如果使用mvc的话,activity将有大量的冗余代码,使用mvp解耦,代码清晰,便于维护。

6、上面对MVP框架进行封装,接下来对Retrofi2.0进行快速封装

6.1、第一步编写Retrofi2.0接口方法,AP地址、具题编写注解方式、和传参方式参考参考网上资料。

/**

* Created by ljp on 2018/9/12.

*

* Retrofit 接口

*/

public interface RetrofitApi {

String API = "http://api.leke.cn/xxx/w/";//TODO api地址 具体拼接方式网上查询资料

/**

* 学段请求

*

* @return 学段名称

*/

@GET("invoke.htm?_s=learn&_m=getStudentAllStages")

Observable>> getStudySectionData();

}

6.2、第二步创建RetrofitApi的实例,

/**

* Created by ljp on 2018/9/12.

*/

public class RetrofitHelper {

private Context mCntext;

private static RetrofitHelper instance = null;

private Retrofit mRetrofit = null;

/**

* 单例

* @param context

* @return

*/

public static RetrofitHelper getInstance(Context context){

if (instance == null){

instance = new RetrofitHelper(context);

}

return instance;

}

private RetrofitHelper(Context context){

mCntext = context;

resetApp();

}

/**

* Retrofit初始化,传入URL地址

*/

private void resetApp() {

mRetrofit = new Retrofit.Builder()

.baseUrl(RetrofitApi.API)

.client(getOkHttpClient())

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

.build();

}

/**

* OkHttpClient

* 这里我们可以传入我们自己的头部名称信息在addHeader添加

*/

private OkHttpClient getOkHttpClient() {

OkHttpClient client = new OkHttpClient.Builder()

.addInterceptor(new Interceptor() {

@Override

public Response intercept(Chain chain) throws IOException {

Request request = chain.request();

Request.Builder builder1 = request.newBuilder();

Request build = builder1.addHeader("xxx","xxx").build();

return chain.proceed(build);

}

}).retryOnConnectionFailure(true).build();

return client;

}

/**

*

* @return RetrofitService接口对象

* 这里就拿到我们需要RetrofitApi对象

*/

public RetrofitApi getRetrofitService(){

return mRetrofit.create(RetrofitApi.class);

}

}

6.3、创建工具类使用Retrofit调用接口方法

/**

* Created by ljp on 2018/9/12.

*

* 网络操作工具类

*/

public class RxHttpUtils {

private RetrofitApi mRetrofitService;

public RxHttpUtils(Context context) {

this.mRetrofitService = RetrofitHelper.getInstance(context).getRetrofitService();

}

public Observable>> getSearchStudnt() {

return mRetrofitService.getStudySectionData();

}

}

6.4、开始使用封装的retrofit,如上代码中的具体mode-StudentMainModelImpl,由于我对retrofit最后一步进行封装,上面StudentMainModelImpl中doHttpStudentSection方法等同下面doHttpStudentSectionTwo方法,这个方法,关键需要加入两个调度方法:

.subscribeOn(Schedulers.io()):I/O操作(读写文件,读写数据库,网络请求等)所使用的scheduler,内部实现一个无上限的线程池,可以重用空闲的线程,因此要比newThread()更有效率,请尽量不要将计算工作放入io()中,避免创建不必要的线程。

.observeOn(AndroidSchedulers.mainThread()): 指定在android的主线程中执行操作

public void doHttpStudentSectionTwo(final NetWorkCallback>

netWorkCallback) {

rxHttpUtils.getSearchStudnt()

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new LekeObserver>>() {

@Override

public void onSucced(Result> listResult) {

}

@Override

public void onFailed(Throwable error) {

}

});

}

框架结构图:

mvp_retrofit_rxjava.png

android中mvp封装,android-简单快速封装MVP+Retrofit2.0+Rxjava框架相关推荐

  1. Android基于Retrofit2.0 +RxJava 封装的超好用的RetrofitClient工具类(六)

    csdn :码小白 原文地址: http://blog.csdn.net/sk719887916/article/details/51958010 RetrofitClient 基于Retrofit2 ...

  2. android中对Toast的简单封装

    // 一般做法 public void showToast(Context context, String msg) { Toast.makeText(context, msg, Toast.LENG ...

  3. android 中自定义安装,Android开发中ListView自定义adapter的封装

    [引入] 我们一般编写listView的时候顺序是这样的: •需要展示的数据集List •为这个数据集编写一个ListView •为这个ListView编写一个Adapter,一般继承自BaseAda ...

  4. Android中PackageManager类的简单介绍

    1.PackageManager这个类,表层意思是包管理者,既然可以管理包,那么包下的一些东西便可以获取,其中可以获取应用图标和应用名称以及包名. 通过下面一行代码实例化PackageManager类 ...

  5. android 中使用AsyncTask实现简单的异步编程

    在开发移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验.但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI ...

  6. 简单Android app开发_如何简单快速开发外卖app?

    如何开发一个外卖app?app开发需要多少钱?随着美团.饿了么的外卖app的发展,对餐饮.生鲜果蔬.超市便利店行业来说,app成为必不可缺少的一部分.与其向第三方交纳一定不开发一个自己的外卖平台.也有 ...

  7. Android中Chronometer计时器的简单使用

    场景 实现效果如下 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 将布局改 ...

  8. android实现runnable接口,Android中实现Runnable接口简单例子

    本课讲的是如何实现一个Runnable,在一个独立线程上运行Runnable.run()方法.Runnable对象执行特别操作有时叫作任务. Thread和Runnable都是基础的类,靠他们自己,能 ...

  9. android中自定义 toast,android 自定义Toast样式和显示方式

    问题: 1.android 开发中如果不停的触发显示Toast,会造成Toast一个接一个的弹出,非常影响用户体验. 2.android设备有千万个,每个设备的Toast的背景有可能不一样,造成在应用 ...

最新文章

  1. php微信菜单40017错误,微信公众号接口添加菜单时错误(errcodequot;:40017 invalid button type) - 好库文摘...
  2. nullnullC++ LANGUAGE TUTORIAL: CHARACTER ARRAYS...
  3. python定义函数的组成部分有_Python基础11- 函数之自定义函数
  4. c语言编程顺序查找例题,C语言典型编程例题.doc
  5. django 1.8 官方文档翻译: 2-3-1 模型实例参考
  6. Css实现页面元素置顶时悬浮
  7. 分享一个自动刷抖音的代码 auto js
  8. psp模拟java_PSP超强JAVA模拟器 PSPKVM v0.5 发布下载
  9. 系统研发类项目标书制作流程--标书该怎么做?
  10. 斐讯路由器刷华硕固件后按复位键无反应,无法设置网络
  11. 盘符修改后,node重装一顿操作猛如虎
  12. (42)2021-03-01(物体运动、swiper软件、自执行函数)
  13. centos 中使用sqlplus 登陆oracle提示bash.sqlplus命令未找到的解决方法
  14. Java网站开发中的DAO是什么意思
  15. PostgreSQL集群方案-citus
  16. TCP:利用Socket编程技术实现客户端向服务端上传一个图片。
  17. C盘临时文件怎么删除?
  18. 白领患上“网聊依赖症”
  19. RapidMiner 离散/缺失
  20. 凯利公式自动计算表_利用凯利公式计算每场投注的最佳比例

热门文章

  1. 听说英飞凌内推技术岗位有大额奖金
  2. 智能车竞赛技术报告 | 智能车视觉 - 南京邮电大学 - 栅库砸车跑路队
  3. 室外电磁赛道铺设补充说明
  4. 注解 java 反射_java注解和反射
  5. mysql 返回的查询结果为空 (即零行)._Mysql数据同步(单向)
  6. python学习笔记项目_python学习笔记——肆
  7. kali 改root_Kali Linux 将默认以非 root 身份运行
  8. 仓库码放要求_货物码放规范
  9. jsp中设置自动换行_微信公众号文章中如何设置自动回复?
  10. Linux 构建一些 开机就可以使用的命令