MVP+RxJava+Retrofit框架的使用及其开源项目推荐

mvp

前面我已经写过一篇关于Google的RxJava版MVP解读的文章,本篇就是我在此基础上进行了修改和封装,稍微变化一下,见上图。目的是让这个框架更加实用,同时简化操作,少写代码。果然程序员都是喜欢偷懒的- -

前言

首先,阅读本篇文章前,建议你先去了解一下MVP这个设计模式。当然,也可以先看看我前面的文章^_^ 传送门

另外,还用到了RxJavaRetrofitOkhttp。如果你已经了解了他们的基本用法,请直接忽略这段,接着往下看~

不想看长长的文章的,可以直接看代码。代码地址已经上传到Github,https://github.com/backkomyoung/MVP

工程结构

按照惯例,先看看工程的主要结构:

project

简单说一下几个主要包下的功能。首先是api包,这是存放对Retrofit进行包装的类。Base包当然是放各种Base类啦~ mvp包是将契约类Contract、Model的实现类和Presenter的实现类放一起,方便管理。其实你也可以按功能分包,个人喜好吧。ui包放一些界面的类,如Activity和Fragment。

下面正式开始~

契约类

同样也是从Contract契约类开始说起:

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
    
public  interface MainContract {
interface View extends BaseView {
void showDialog();
void onSucceed(Gank data);
void onFail(String err);
void hideDialog();
}
interface Model extends BaseModel {
Observable<Gank> getGank();
}
abstract  class Presenter extends BasePresenter<ViewModel{
public abstract void getGank();
}
}

我们可以看到,整体上和Google的Demo差不多,都是把View和Presenter放到Contract类里面统一管理,我这里多加了个Model接口,我不推荐在Presenter进行Model操作,本来很优雅的一件事,在Presenter进行Model操作的话,感觉就差了很多,要做一个优雅的程序员。不同的地方是Model和View接口继承了BaseModel接口和BaseView接口,Presenter变成了一个抽象类,继承于BasePresenter抽象类,传入两个泛型View、Model。为啥呢?我们接着看Base包下的三个Base类。

Base类

BaseModel:

 
    
1
2
 
    
public  interface BaseModel {
}

BaseView:

 
    
1
2
 
    
public  interface BaseView {
}

BasePresenter:

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
    
public  class BasePresenter<V extends BaseViewM extends BaseModel{
protected V mView;
protected M mModel;
private CompositeSubscription mCompositeSubscription;
protected void addSubscribe(Subscription subscription) {
if (mCompositeSubscription ==  null) {
mCompositeSubscription =  new CompositeSubscription();
}
mCompositeSubscription.add(subscription);
}
public void unSubscribe() {
if (mView !=  null) {
mView =  null;
}
if (mCompositeSubscription !=  null && mCompositeSubscription.hasSubscriptions()) {
mCompositeSubscription.clear();
}
}
}

BaseModel和BaseView接口里面是空的,在这里我只是为了在BasePresenter中提供一个约束。当然,如果你有其它全局的需求,可以在里面添加一些方法。重点是BasePresenter这个抽象类,传入一个View和Model,并将其用protected关键字修饰,这样,在它的子类中就可以直接对其赋值和使用了。加入CompositeSubscription变量,是为了对RxJava进行管理。unSubscribe方法对View进行null赋值和清除Rx的Subscription(订阅),防止内存泄漏。

Presnter桥梁

接下来看看这个很重要的类,作为连接Model和View的桥梁,这里又是怎么做的呢?

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 
    
public  class MainPresenter extends MainContract.Presenter {
public MainPresenter(MainContract.View view) {
mView = view;
mModel =  new MainModel();
}
@Override
public void getGank() {
Subscription subscribe = mModel.getGank()
.subscribe( new Subscriber<Gank>() {
@Override
public void onStart() {
mView.showDialog();
}
@Override
public void onCompleted() {
mView.hideDialog();
}
@Override
public void onError(Throwable e) {
mView.onFail(e.getMessage());
onCompleted();
}
@Override
public void onNext(Gank gank) {
mView.onSucceed(gank);
}
});
addSubscribe(subscribe);
}
}

构造方法传进一个View,并且new了一个Model对象,直接赋值给父类中的View和Model。然后下面复写的方法中调用Model中的方法,再将结果通过View中的方法传出去,这是很原始的MVP方式。最后addSubscribe添加到订阅队列中。

Model处理数据

Model分出来,而不在Presenter处理,其实也是为了简洁,当你要处理很多数据的时候,Presenter就会变得很乱了。

 
    
1
2
3
4
5
6
7
8
9
 
    
public  class MainModel implements MainContract.Model {
@Override
public Observable<Gank> getGank() {
return ApiEngine.getInstance().getApiService()
.getGank( "1")
.compose(RxSchedulers.<Gank>switchThread());
}
}

我这里很简单,就获取ApiService对象,然后调用API。最后compose传进我自己定义的线程切换器:

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
    
public  class RxSchedulers {
public  static <T> Observable. Transformer<T, T> switchThread() {
return  new Observable.Transformer<T, T>() {
@Override
public Observable<T> call(Observable<T> tObservable) {
return tObservable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}

将网络请求的IO线程切换回Android的UI主线程,才能继续进行在Presenter中的操作。

BaseActivity中的封装

在前面我们可以看到BasePresenter中有两个方法,一个是添加订阅addSubscribe,另一个是unSubscribe解除订阅。我们只看到了在Presenter中使用了addSubscribe,而没有看到unSubscribe在哪使用了。因为要防止内存泄漏,所以当然要在和生命周期相关的地方进行释放资源,这个地方只有我们所说的View了,也就是Activity和Fragment中。我们先开看一下相关代码:

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
    
public  abstract  class BaseActivity<P extends BasePresenterextends AppCompatActivity {
protected P mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (onCreatePresenter() !=  null) {
mPresenter = onCreatePresenter();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mPresenter!= null){
mPresenter.unSubscribe();
}
}
protected abstract P onCreatePresenter();
}

通过泛型确定一个Presenter的类型,然后使用抽象方法onCreatePresenter对其进行赋值,最后在onDestroy方法中进行资源的释放。继承这个BaseActivity类的Activity,就不用每次都在onDestroy进行同样的操作啦~达到简洁的目的。同理,Fragment中也是同样的,只是在生命周期的onResume和onPause中分别进行Presenter的赋值和资源的释放。这里我就不贴代码,可以上我的Github看。

Retrofit引擎封装

说到这了,就顺便说一下Retrofit吧。上面的MainModel类中用到了ApiEngine类:

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
    
public  class ApiEngine {
private  volatile  static ApiEngine apiEngine;
private Retrofit retrofit;
private ApiEngine() {
//日志拦截器
HttpLoggingInterceptor loggingInterceptor =  new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//缓存
int size =  1024 *  1024 *  100;
File cacheFile =  new File(App.getContext().getCacheDir(),  "OkHttpCache");
Cache cache =  new Cache(cacheFile, size);
OkHttpClient client =  new OkHttpClient.Builder()
.connectTimeout( 12, TimeUnit.SECONDS)
.writeTimeout( 12, TimeUnit.SECONDS)
.writeTimeout( 12, TimeUnit.SECONDS)
.addNetworkInterceptor( new NetworkInterceptor())
.addInterceptor(loggingInterceptor)
.cache(cache)
.build();
retrofit =  new Retrofit.Builder()
.baseUrl(ApiService.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
public static ApiEngine getInstance() {
if (apiEngine ==  null) {
synchronized (ApiEngine.class) {
if (apiEngine ==  null) {
apiEngine =  new ApiEngine();
}
}
}
return apiEngine;
}
public ApiService getApiService() {
return retrofit.create(ApiService.class);
}
}

用了单例模式,在构造方法中只初始化一次Retrofit和Okhttp。双重锁的方式获取单例,然后再根据需要获取ApiService,如果你有很多个不同源的API,那就可以创建多个getXXXXApiService。

结语

最后,来看看Demo运行效果吧:

demo_gif

Demo数据源来自Gank.io

其实还有一个问题,就是关于错误类型的统一处理。刚开始的时候我是打算添加进去的,但是后来想想,每个项目的API都有不同的需求,有不同的错误,所以,还是留给需要的时候再封装一层错误处理吧。如果要统一处理错误,自定义一个Subscriber,在里面的onError方法处理即可。

推荐MVP开源项目:

MVP做一款阅读类的app

MVP新闻阅读app

MVPArms

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MVP(Model View Presenter)其实就是一种项目的整体框架,能让你的代码变得更加简洁,说起框架大家可能还会想到MVC、MVVM。由于篇幅原因,这里我们先不讲MVVM,先来看一下MVC。其实Android本身就采用的是MVC(Model View Controllor)模式、其中Model指的是数据逻辑和实体模型;View指的是布局文件、Controllor指的是Activity。对于很多Android初学者可能会有这样的经历,写代码的时候,不管三七二十一都往Activity中写,当然我当初也是这么干的,根本就没有什么框架的概念,只要能实现某一个功能就很开心了,没有管这么多。当然项目比较小还好,一旦项目比较大,你会发现,Activity所承担的任务其实是很重的,它既要负责页面的展示和交互,还得负责数据的请求和业务逻辑之类的工作,相当于既要打理家庭,又要教育自己调皮的孩子,真是又当爹又当妈。。。那该怎么办呢?这时候Presenter这个继父来到了这个家庭。Presenter对Activity说,我来了,以后你就别这么辛苦了,你就好好打理好View这个家,我专门来负责教育Model这孩子,有什么情况我会向你反映的。这时Activity流下了幸福的眼泪,从此,Model、View(Activity)、Presenter一家三口过上了幸福的生活。。。好了磕个药继续,由于Presenter(我们自己建的类)的出现,可以使View(Activity)不用直接和Model打交道,View(Activity)只用负责页面的显示和交互,剩下的和Model交互的事情都交给Presenter做,比如一些网络请求、数据的获取等,当Presenter获取到数据后再交给View(Activity)进行展示,这样,Activity的任务就大大减小了。这便是MVP(Model 还是指的数据逻辑和实体模型,View指的是Activity,P就是Presenter)框架的工作方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值