Mvp+RxJava2+Retrofit2 搭建一个属于自己的开发框架
2017-09-09 11:30
190 查看
许多不管怎么做、怎么想都没结果的事,要懂得交给时间。有些事无论你怎么努力怎么勉强,时间不够,还是耐心的等待吧。
这张图可以说是看烂了,这张图对于懂了点MVP的人可以说是把中间几个字去掉,都能一眼看穿。这张图到底是什么意思呢?
普通做法:
一个Activity中写一个方法访问网络获取数据,点击按钮调用它,然后获取数据完成了再拿到对应的控件设置数据,完事了。。。
MVP:
在图中有三个模块view(界面),presenter(控制层),model(数据源)。他们在这个需求中需要做什么呢?
view(界面):显示数据
presenter(控制层):1.通知model我要取数据 2.取到了数据再传递给view
model(数据源):访问网络获取数据
presenter告诉model我要数据
model访问网络得到了数据再通知presenter给你我取到的数据
presenter 处理好数据 再把数据传递给view
最后view显示出来用户可以观看。
这确实有点复杂,在面向对象中有几个原则 单一职责原则,开闭原则,里氏代换原则,依赖倒转原则,接口隔离原则,合成复用原则,迪米特法则。这我就不一一介绍了,自行百度。。普通做法中一个Activity即有访问网络,又有更新界面,第一条单一职责原则就违背了,然而在mvp中view只做和界面相关的事情。
再者一个Activity中如果逻辑太多了。一个Activity几千行代码,逻辑判断,更新界面,查询数据库,访问网络,如果第二个人需要修改,怎么看??
这时候再看看mvp 逻辑在P里面一个类,数据在Model层,界面相关的在V层。清晰明了,也方便单元测试。
程序猿如果不最求代码质量,那和咸鱼有什么区别?
单独使用retrofit是返回call,配合RxJava这里我们返回Observable
好我们来分析一下,
首先先获得一个retrofitService对象
然后调用test接口。
访问网络在子线程
在访问网络的时候显示等待对话框,将这个请求加入CompositeDisposable中(在basePresenter封装了统一管理的方法,调用addDisposable(disposable);最后Activity关闭,取消所有网络请求,防止内存泄漏)
将网络获取的数据转换成你需要的数据
线程卡点结果返回主线程
订阅得到数据更新界面,处理错误信息
RxJava2+retrofit2就是这么简单封装好了一条线路下来非常清晰。没用过的朋友看下有可能一脸懵逼,不过没关系,你只要拿着我的项目看下就能懂了。
2.presenter需要给view数据,那么presenter也需要一个view对象。
3.model层访问网络使用RxJava+retrofit,数据回调给presenter(后面分析)
暂时在我的需求中view和presenter只有如下这么几个功能,当然,如果你还有其他的功能可以再加上去。
所以我们先看下代码:
创建activity中泛型传入相应的view接口,presenter中泛型传入相应的presenter接口
activity中onCreate中初始化presenter,onDestroy中调用detach,将presenter中正在执行的任务取消,将view对象置为空。
presenter中通过构造传递参数。将view的实例传递进入presenter
首先我们先来个简单的需求:
打开一个页面请求网络获取数据,将数据显示在界面上
创建Contact管理接口
首先先思考view需要设置数据所有view中需要一个setData方法
presenter需要去访问网络所以需要一个getData方法。代码如下:
创建一个TestPresenter继承BasePresenterImpl,泛型对应view的接口。并实现对应的presenter接口
代码如下:
创建对应的类,实现对应的方法
Activity中只有一个recyclerView初始化它。
在onCreate中调用presenter中的getData()方法
在presenter中使用RxJava2+retrofit2访问网络。获取数据返回给view
view拿到数据更新界面
一:序言
2016年安卓热门词汇MVP,RxJava,Retrofit。时隔一年这些框架依然是很常用的,现在来把这几个关键词整合起来,搭建一个快速开发框架。。。二: MVP是什么?
对于一些刚学安卓的朋友们应该还不是太熟悉,我们先来温习一下吧!这张图可以说是看烂了,这张图对于懂了点MVP的人可以说是把中间几个字去掉,都能一眼看穿。这张图到底是什么意思呢?
举个例子:
需求:需要点击一个按钮通过访问网络获取一条数据展示在页面上普通做法:
一个Activity中写一个方法访问网络获取数据,点击按钮调用它,然后获取数据完成了再拿到对应的控件设置数据,完事了。。。
MVP:
在图中有三个模块view(界面),presenter(控制层),model(数据源)。他们在这个需求中需要做什么呢?
view(界面):显示数据
presenter(控制层):1.通知model我要取数据 2.取到了数据再传递给view
model(数据源):访问网络获取数据
它的过程是这样的,
view告诉presenter我要数据presenter告诉model我要数据
model访问网络得到了数据再通知presenter给你我取到的数据
presenter 处理好数据 再把数据传递给view
最后view显示出来用户可以观看。
这确实有点复杂,在面向对象中有几个原则 单一职责原则,开闭原则,里氏代换原则,依赖倒转原则,接口隔离原则,合成复用原则,迪米特法则。这我就不一一介绍了,自行百度。。普通做法中一个Activity即有访问网络,又有更新界面,第一条单一职责原则就违背了,然而在mvp中view只做和界面相关的事情。
再者一个Activity中如果逻辑太多了。一个Activity几千行代码,逻辑判断,更新界面,查询数据库,访问网络,如果第二个人需要修改,怎么看??
这时候再看看mvp 逻辑在P里面一个类,数据在Model层,界面相关的在V层。清晰明了,也方便单元测试。
程序猿如果不最求代码质量,那和咸鱼有什么区别?
三: RxJava2+Retrofit2整合
1.玩框架第一步compile :
compile 'io.reactivex.rxjava2:rxjava:2.1.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:converter-scalars:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合rxjava2 compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'//拦截器
2.创建service
public interface RetrofitService { String BASE_URL = "https://news-at.zhihu.com/api/4/"; /** * 测试接口 * * @return */ @GET("news/latest") Observable<TestBean> test(); }
单独使用retrofit是返回call,配合RxJava这里我们返回Observable
3.封装一个工具类
public class RetrofitFactory { //访问超时 private static final long TIMEOUT = 30; // Retrofit是基于OkHttpClient的,可以创建一个OkHttpClient进行一些配置 private static OkHttpClient httpClient = new OkHttpClient.Builder() //打印接口信息,方便接口调试 .addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { Log.e("TAG", "log: " + message); } }).setLevel(HttpLoggingInterceptor.Level.BASIC)) .connectTimeout(TIMEOUT, TimeUnit.SECONDS) .readTimeout(TIMEOUT, TimeUnit.SECONDS) .build(); private static RetrofitService retrofitService = new Retrofit.Builder() .baseUrl(RetrofitService.BASE_URL) // 添加Gson转换器 .addConverterFactory(GsonConverterFactory.create(new GsonBuilder() .setLenient() .create() )) // 添加Retrofit到RxJava的转换器 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(httpClient) .build() .create(RetrofitService.class); //获得RetrofitService对象 public static RetrofitService getInstance() { return retrofitService; } }
4.使用
我们整合好了,最后我们看下怎么使用吧!访问个网络获取一个数据RetrofitFactory.getInstance()//获取retrofitService对象 .test()//测试接口 .subscribeOn(Schedulers.io()) .doOnSubscribe(new Consumer<Disposable>() { @Override public void accept(@NonNull Disposable disposable) throws Exception { //将这个请求的Disposable添加进入CompositeDisposable同一管理(在封装的presenter中) addDisposable(disposable); //访问网络显示dialog view.showLoadingDialog(""); } }) .map(new Function<TestBean, List<TestBean.StoriesBean>>() { @Override public List<TestBean.StoriesBean> apply(@NonNull TestBean testBean) throws Exception { //转化数据 return testBean.getStories(); } }) //获得的数据返回主线程去更新界面 .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<List<TestBean.StoriesBean>>() { @Override public void accept(@NonNull List<TestBean.StoriesBean> storiesBeen) throws Exception { //消失dialog view.dismissLoadingDialog(); //设置数据 view.setData(storiesBeen); } }, new Consumer<Throwable>() { @Override public void accept(@NonNull Throwable throwable) throws Exception { view.dismissLoadingDialog(); String exception = ExceptionHelper.handleException(throwable); //打印出错误信息 Log.e("TAG", "exception: " + exception); } });
好我们来分析一下,
首先先获得一个retrofitService对象
然后调用test接口。
访问网络在子线程
在访问网络的时候显示等待对话框,将这个请求加入CompositeDisposable中(在basePresenter封装了统一管理的方法,调用addDisposable(disposable);最后Activity关闭,取消所有网络请求,防止内存泄漏)
将网络获取的数据转换成你需要的数据
线程卡点结果返回主线程
订阅得到数据更新界面,处理错误信息
RxJava2+retrofit2就是这么简单封装好了一条线路下来非常清晰。没用过的朋友看下有可能一脸懵逼,不过没关系,你只要拿着我的项目看下就能懂了。
四: 打造MVP
先看下我们的成果里面有什么东西吧!没错 就是下面几个类就ok五:分析
好我们来分析一下mvp
1.view需要找presenter拿数据,那么view里面需要一个presenter对象。2.presenter需要给view数据,那么presenter也需要一个view对象。
3.model层访问网络使用RxJava+retrofit,数据回调给presenter(后面分析)
思考
所有的view里面都需要什么操作呢? 所有的presenter里面都需要什么操作呢?暂时在我的需求中view和presenter只有如下这么几个功能,当然,如果你还有其他的功能可以再加上去。
public interface BaseView { //显示dialog void showLoadingDialog(String msg); //取消dialog void dismissLoadingDialog(); }
public interface BasePresenter { //默认初始化 void start(); //Activity关闭把view对象置为空 void detach(); //将网络请求的每一个disposable添加进入CompositeDisposable,再退出时候一并注销 void addDisposable(Disposable subscription); //注销所有请求 void unDisposable(); }
五:接下来编写view和presenter的实现类
由于每一个view都对应不同的presenter。当然对应的每个presenter也同样对应一个view。所有我们使用接口和泛型来封装了。所以我们先看下代码:
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView { protected P presenter; public Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); context = this; ActivityManager.getAppInstance().addActivity(this);//将当前activity添加进入管理栈 presenter = initPresenter(); } @Override protected void onDestroy() { ActivityManager.getAppInstance().removeActivity(this);//将当前activity移除管理栈 if (presenter != null) { presenter.detach();//在presenter中解绑释放view presenter = null; } super.onDestroy(); } /** * 在子类中初始化对应的presenter * * @return 相应的presenter */ public abstract P initPresenter(); @Override public void dismissLoadingDialog() { } @Override public void showLoadingDialog(String msg) { } }
public abstract class BasePresenterImpl<V extends BaseView> implements BasePresenter { public BasePresenterImpl(V view) { this.view = view; start(); } protected V view;//给子类使用view @Override public void detach() { this.view = null; unDisposable(); } @Override public void start() { } -----------------------我是分割线-------------------------------- //以下下为配合RxJava2+retrofit2使用的 //将所有正在处理的Subscription都添加到CompositeSubscription中。统一退出的时候注销观察 private CompositeDisposable mCompositeDisposable; /** * 将Disposable添加 * * @param subscription */ @Override public void addDisposable(Disposable subscription) { //csb 如果解绑了的话添加 sb 需要新的实例否则绑定时无效的 if (mCompositeDisposable == null || mCompositeDisposable.isDisposed()) { mCompositeDisposable = new CompositeDisposable(); } mCompositeDisposable.add(subscription); } /** * 在界面退出等需要解绑观察者的情况下调用此方法统一解绑,防止Rx造成的内存泄漏 */ @Override public void unDisposable() { if (mCompositeDisposable != null) { mCompositeDisposable.dispose(); } } }
创建activity中泛型传入相应的view接口,presenter中泛型传入相应的presenter接口
activity中onCreate中初始化presenter,onDestroy中调用detach,将presenter中正在执行的任务取消,将view对象置为空。
presenter中通过构造传递参数。将view的实例传递进入presenter
六:使用
好的接下来我们来使用一下吧首先我们先来个简单的需求:
打开一个页面请求网络获取数据,将数据显示在界面上
创建Contact管理接口
首先先思考view需要设置数据所有view中需要一个setData方法
presenter需要去访问网络所以需要一个getData方法。代码如下:
public interface TestContact { interface view extends BaseView { /** * 设置数据 * * @param dataList */ void setData(List<TestBean.StoriesBean> dataList); } interface presenter extends BasePresenter { /** * 获取数据 */ void getData(); } }
创建Activity和presenter
创建一个Activity继承BaseActivity它的泛型对应presenter的接口。实现对应的view接口创建一个TestPresenter继承BasePresenterImpl,泛型对应view的接口。并实现对应的presenter接口
代码如下:
public class TestActivity extends BaseActivity<TestContact.presenter> implements TestContact.view { private List<TestBean.StoriesBean> list = new ArrayList<>();//数据 private RecyclerView recyclerView; private TestAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); init(); presenter.getData(); } /** * 初始化界面 */ private void init() { recyclerView = (RecyclerView) findViewById(R.id.recycleview); recyclerView.setLayoutManager(new LinearLayoutManager(this)); adapter = new TestAdapter(list); recyclerView.setAdapter(adapter); } /** * 初始化presenter * * @return 对应的presenter */ @Override public TestContact.presenter initPresenter() { return new TestPresenter(this); } /** * 设置数据 * 刷新界面 * * @param dataList 数据源 */ @Override public void setData(List<TestBean.StoriesBean> dataList) { list.addAll(dataList); adapter.notifyDataSetChanged(); } }
public class TestPresenter extends BasePresenterImpl<TestContact.view> implements TestContact.presenter { public TestPresenter(TestContact.view view) { super(view); } /** * 获取数据 */ @Override public void getData() { Api.getInstance() .test()//测试接口 .subscribeOn(Schedulers.io()) .doOnSubscribe(new Consumer<Disposable>() { @Override public void accept(@NonNull Disposable disposable) throws Exception { addDisposable(disposable);//请求加入管理 view.showLoadingDialog(""); } }) .map(new Function<TestBean, List<TestBean.StoriesBean>>() { @Override public List<TestBean.StoriesBean> apply(@NonNull TestBean testBean) throws Exception { return testBean.getStories();//转换数据 } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<List<TestBean.StoriesBean>>() { @Override public void accept(@NonNull List<TestBean.StoriesBean> storiesBeen) throws Exception { view.dismissLoadingDialog(); view.setData(storiesBeen); } }, new Consumer<Throwable>() { @Override public void accept(@NonNull Throwable throwable) throws Exception { view.dismissLoadingDialog(); ExceptionHelper.handleException(throwable); } }); } }
七:分析
好了相信大部分朋友看了代码都看懂了,简要的分析一下过程吧创建对应的类,实现对应的方法
Activity中只有一个recyclerView初始化它。
在onCreate中调用presenter中的getData()方法
在presenter中使用RxJava2+retrofit2访问网络。获取数据返回给view
view拿到数据更新界面
请接受我双手奉上的源码地址
相关文章推荐
- 简易Mvp+RxJava2+Retrofit2 搭建一个属于自己的开发框架
- android框架搭建——封装一个属于自己的数据存储工具类(SQLite篇)
- 用.Net打造一个移动客户端(Android/IOS)的服务端框架NHM(三)——搭建Android开发环境,用Hibernate生成Android项目的Model层
- 从零开始搭建一个完善的MVP开发框架
- 基于springboot+redis+bootstrap+mysql开发一套属于自己的分布式springcloud云权限架构(十七)【权限架构系统(基础框架搭建)】
- SSM框架——Spring+SpringMVC+Mybatis的搭建教程 一:概述 SSM框架在项目开发中经常使用到,相比于SSH框架,它在仅几年的开发中运用的更加广泛。 Spring作为一个轻量级
- 【微信开发】02.搭建一个属于自己的微信公众平台
- 基于vue-cli网上商城项目实战开发——搭建一个完整的SPA项目开发框架(一)
- 在Android开发过程中搭建一个自己的应用框架有几个步骤?需要注意什么?
- OpenGL + Win32 SDK 开发框架的搭建(C++语言版)(先补上一个问题!!)
- 动手写一个Python Web 框架学习笔记 - 搭建开发环境 (1)
- retrofit与rxjava搭建的网络框架使用的一个小技巧
- 从零开始搭建 一个完善的 MVP模式开发框架(一),MVP模式的简单介绍篇
- 手把手教你如何搭建一个自己的安卓快速开发框架之BaseActivity(一)
- 从零开始搭建一个完善的MVP开发框架(二),通过泛型和抽象,简化MVP框架。
- 从零开始搭建一个完善的MVP开发框架(三),对列表型数据请求进行抽象,优化列表型数据的处理
- 手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(三)
- 手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(四)
- 手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(二)
- 【微信开发】02.搭建一个属于自己的微信公众平台