RxJava+Retrofit+RxLifecycle实现mvp+网络请求。

RxJava+Retrofit+MVP框架。

  • 第一次写博客,写的不好请各位看官见谅,如有错误,欢迎批评指正~

    简介:RxJava和Retrofit可谓目前Android最火的两大框架了。本文只对两者的使用做一个简单的实例,侧重于两者结合对网络请求的封装,各自高深的用法和源码还请各位看官度娘之~。

一:基础篇

  • 好啦,废话不多说,先上依赖代码。
    implementation "com.squareup.okhttp3:logging-interceptor:3.9.0"
    implementation "com.squareup.retrofit2:retrofit:2.3.0"
    implementation "com.squareup.retrofit2:converter-gson:2.3.0"
    implementation "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
    implementation "io.reactivex.rxjava2:rxjava:2.0.6"
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'
    implementation "com.trello.rxlifecycle2:rxlifecycle:2.2.1"
    implementation "com.trello.rxlifecycle2:rxlifecycle-components:2.2.1"
    implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
  • RxJava的基本使用
    使用之前,先让我们来看下官方对RxJava的定义。它是干嘛的啊:
    在这里插入图片描述
    好吧,我承认我看完之后依旧是一脸懵逼。这特么是啥玩意啊。

    在这里插入图片描述

无奈去了github官网看了下,找了几个demo。地址如下:https://github.com/ReactiveX/RxJava。

根据几个demo总结下来,基本可以得出以下几点:

  • RxJava是基于观察者和被观察者模式,观察者和被观察者之间存在一种订阅的关系,观察者可以知道被观察者某种事件下所发生的一切。何谓某种事件下呢?举个例子:你老婆拿着你的工资卡去商场购物,买了一个两万块钱的包包,这时候你就可以收到银行发来的一条消费两万元的短信,然后暗骂一句败家娘们。这个时候你就是观察者,你老婆就是被观察者。但你不可能观察你老婆所有的事情吧,比如问了个路、喝了杯咖啡等等,这些你老婆不告诉你你是不会知道的,你能知道的仅仅是你老婆花了两万块钱买了个很贵的包而已。凡是你卡里余额变动,你都能知道,我们可以说这是基于银行卡余额变动事件下的观察者模式。总结四个字:基于事件

  • RxJava它是异步的。这个比较好理解,就好像我去蛋糕店买蛋糕,我跟老板说了我想要什么样的蛋糕,然后我告诉老板我什么时候来取,不必一直在蛋糕店里等着,我可以去忙其它的事,这就是异步。

  • 被观察者是可以通过某种操作符转变的,好像很难理解啊。还是上面那个例子:你老婆回到家,你当面骂了你老婆一句你个败家娘们,然后你老婆把你打了一顿。你可能会说,我老婆打我跟这个有毛线关系啊。好吧,让我们来分析一下:本来你在心里暗骂,你老婆听不见,也不会打你,可你非得作死的操作了一波(当面骂她),你就是通过当面骂这个操作成功激怒你老婆,变身母老虎,把你揍了一顿。老婆->母老虎。这就是转变。RxJava中也内置了许多操作符,可以把被观察者进行转变,转变为另外一种形态,咱们下面再说。

说了半天,RxJava到底怎么用呢?


在这里插入图片描述

来,让我们一二三三步走。

  1. 创建被观察者。
 Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                 //把这个消息发送出去。
                emitter.onNext("我花了两万块钱买了个包");
            }
        });
  1. 创建观察者。
 Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String msg) {
                //你收到买包的消息。
                Log.e("RxJava--------------",msg);
                //你暗骂的话。
                Log.e("RxJava--------------","收到了,败家娘们");

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        };
  1. 订阅,以便观察者能收到消息。这里比较奇怪的是被观察者订阅观察者,按照一般人的逻辑是观察者订阅被观察者,可能框架的设计者有什么其它的考量吧。
//订阅。
observable.subscribe(observer);

ok,让我们来看下结果。
在这里插入图片描述
当然这些代码也可以连起来写,RxJava支持链式调用,就像下面这样:

 Observable.create((ObservableOnSubscribe<String>) emitter -> {
            //通知你买了个两万块钱的包。
            emitter.onNext("我花了两万块钱买了个包");
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String msg) {
                //你收到买包的消息。
                Log.e("RxJava--------------", msg);
                //你暗骂的话。
                Log.e("RxJava--------------", "收到了,败家娘们");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });

好了,说完最基本的使用,咱们再来说说转化,此处只举一个例子,RxJava有很多操作符,分别可以实现不同的功能,这里只介绍一种,map操作符。让各位看官有个印象。如果感兴趣,可移步RxJava操作符,还是刚刚上面的代码,稍微加一点。

Observable.create((ObservableOnSubscribe<String>) emitter -> {
            //通知你买了个两万块钱的包。
            emitter.onNext("我花了两万块钱买了个包");
        }).map(new Function<String, String>() {
            @Override
            public String apply(String s) throws Exception {
                //map操作符变换了下,在原来的字符串上加了  "哈哈哈哈哈哈哈哈哈哈哈哈"。
                return s + "哈哈哈哈哈哈哈哈哈哈哈哈";
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String msg) {
                //你收到买包的消息。因为通过map转化过,所以收到的消息,是之前的消息+新增的字符串
                Log.e("RxJava--------------", msg);
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });

结果如下:


在这里插入图片描述

map操作符中传入一个Function对象,需要分别传入两个泛型,第一个泛型是你最开始的被观察者的泛型,后面一个泛型是你通过map操作符转换之后想要变成的被观察者的泛型。我这里是字符串转字符串,只是加了一点点信息而已,可以转化成任意类型,比如转化成一个对象,怎么弄呢?

Observable.create((ObservableOnSubscribe<String>) emitter -> {
            //通知你买了个两万块钱的包。
            emitter.onNext("我花了两万块钱买了个包");
        }).map(new Function<String, MyBean>() {
            @Override
            public String apply(String s) throws Exception {
                //将字符串封装成一个对象
                MyBean bean = new MyBean();
                bean.setWords(s);
                return bean;
            }
        }).subscribe(new Observer<MyBean >() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(MyBean bean) {
                //你收到买包的消息。因为通过map转化成了MyBean对象,所以这里可以直接取到转换后的值。
                Log.e("RxJava--------------", bean.getWords());
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });

MyBean代码:


在这里插入图片描述

而且被观察者也可以通过多种操作符转化多次。因为重点不在这里,RxJava的基本使用到此为止,感兴趣的可以看一看这一篇博客Rxjava2具体使用


在这里插入图片描述

  • Retrofit的基本使用
    1.创建Retrofit对象,采用建造者模式。(测试api采用鸿洋的玩Android的api),api地址
Retrofit retrofit = new Retrofit.Builder()
        //设置baseUrl,baseUrl+接口中配置的地址组成真正的请求地址。
        .baseUrl("http://wanandroid.com/")
        .client(new OkHttpClient())
        .build();
  1. 创建请求接口,这里是通过注解的方式获取到请求类型,参数等信息,所有的请求参数都可以在这里进行配置,然后框架层根据这些信息封装成一个Request对象,发给服务端,具体更详细的用法可以看看这个Retrofit基本使用
package project.hx.com.rxjava;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;

public interface WanAndroidService {
    /**
     * 获取公众号列表
     * @Call<ResponseBody>
     */
    @GET("wxarticle/chapters/json")
    //baseUrl+接口中配置的地址组成真正的请求地址。
    Call<ResponseBody> getPublicAccountList();
}

  1. 创建请求接口对象。
 WanAndroidService service = retrofit.create(WanAndroidService.class);
 
 Call<ResponseBody> responseBodyCall = service.getPublicAccountList();
  1. 发送请求
   responseBodyCall.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    Log.e("玩Android数据-------",response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {

            }
        });

下面看下格式化后的数据:

{
	"data": [{
		"children": [],
		"courseId": 13,
		"id": 408,
		"name": "鸿洋",
		"order": 190000,
		"parentChapterId": 407,
		"userControlSetTop": false,
		"visible": 1
	}, {
		"children": [],
		"courseId": 13,
		"id": 421,
		"name": "互联网侦察",
		"order": 190010,
		"parentChapterId": 407,
		"userControlSetTop": false,
		"visible": 1
	}],
	"errorCode": 0,
	"errorMsg": ""
}

然而


在这里插入图片描述

别急啊大兄弟,这只是Retrofit单独的使用方法,如果要配合RxJava该怎么用呢?很简单。在初始化Retrofit的时候,加两行代码,如下:

Retrofit retrofit = new Retrofit.Builder()
        //设置baseUrl,baseUrl+接口中配置的地址组成真正的请求地址。
        .baseUrl("http://wanandroid.com/")
        .client(new OkHttpClient())
        .addConverterFactory(GsonConverterFactory.create()) // 支持Gson解析
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava2
        .build();

至于请求接口的代码也要稍微改动一下,像下面这样:

public interface WanAndroidService {
    /**
     * 获取公众号列表
     * @return  Observable<PublicAccountBean>
     */
    @GET("wxarticle/chapters/json")
    Observable<PublicAccountBean> getPublicAccountList();
}

GsonConverterFactory的作用是将请求的结果转化成具体的JavaBean。至于Observable,是不是很熟悉?对,它就是RxJava中的被观察者,RxJava2CallAdapterFactory是将该javaBean的对象再封装成Observable,中间经历了两次转化。让我们看下最终的调用:

 WanAndroidService service = retrofit.create(WanAndroidService.class);
        service.getPublicAccountList()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<PublicAccountBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(PublicAccountBean publicAccountBean) {
                        //请求成功
                        for (int i = 0; i < publicAccountBean.getData().size(); i++) {
                            Log.e("data----------", publicAccountBean.getData().get(i).getName());
                        }

                    }

                    @Override
                    public void onError(Throwable e) {
                        //失败
                    }

                    @Override
                    public void onComplete() {
                    }
                });

来看下最终的数据:


在这里插入图片描述

这样就实现了RxJava和Retrifit的搭配使用,同样RxJava是异步的,所以我们可以在onNext方法中再去执行请求成功之后的操作。这里RxJava直接把转化成javaBean和Observable都给你做了,你拿到最终的对象用就完事儿了,还能调用RxJava的api,各种转换各种浪,如果这样还不能吸引你的话。。。


在这里插入图片描述

好了,以上就是RxJava和Retrofit的基本使用,还有个RxLifecycle。它的作用主要是用来解决RxJava引起的内存泄漏。RxJava发布一个订阅后,页面finish时,如果没有取消订阅,或导致Activity或者Frament无法回收,从而导致内存泄漏。解决办法可以在onDestroy为每个观察者取消订阅。但万一有很多呢,有可能会有遗漏,我们可以在使用RxJava时就对观察者进行绑定,一旦Activity或Frament进入某个生命周期,让该观察者取消订阅。举个例子?

 Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                //在Activity  onDestroy时解除订阅,防止内存泄漏。
                .compose(RxLifecycle.bindUntilEvent(BehaviorSubject.create(), ActivityEvent.DESTROY))
                .subscribe();

就一句代码的事,基础篇完事儿了。擦,基础篇竟然写了这么多。。。。。


在这里插入图片描述

二. 封装篇
走你~
至于mvp在此处就不在赘述了,网上也有许多博客。在传统的mvc模式中,Activity往往既充当表现层,又充当逻辑管理层。当逻辑和界面交互逻辑过于复杂的时候,Activity中的代码就会很臃肿,不便于维护。而mvp是将Activity只当做ui表现层,逻辑处理的代码剥离开来,放在一个新的类中,我们称之为Presenter,是MVP中的P层。Activity持有该类的对象,同时该类也能调用Activity中的代码,这样便将逻辑代码和ui交互代码分开,便于开发和维护。好了,话不多说,下面进入正题。

  • 首先创建一个Retrofit管理类,将Retrofit、OkHttpClient和请求接口的构建放一起。
public class RetrofitManager {
    private Retrofit mRetrofit;

    private static class InstanceHelper {
        static RetrofitManager instance = new RetrofitManager();
    }

    public static RetrofitManager getInstance() {
        return InstanceHelper.instance;
    }

    private RetrofitManager() {
        mRetrofit = new Retrofit.Builder()
                //设置baseUrl
                .baseUrl("http://wanandroid.com/")
                //设置OkHttpClient对象
                .client(createOkhttpClient())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava
                .addConverterFactory(GsonConverterFactory.create()) // 支持Gson解析
                .addConverterFactory(ScalarsConverterFactory.create())//支持字符串
                .build();
    }

    /*
    * 创建OkHttpClient对象。Retrofit底层基于OkHttpClient进行网络请求。
    * */
    private OkHttpClient createOkhttpClient() {
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
        return new OkHttpClient.Builder()
                //设置连接超时时间
                .connectTimeout(30, TimeUnit.SECONDS)
                //设置读取超时时间
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                //添加日志过滤器
                .addInterceptor(httpLoggingInterceptor)
                //添加BaseInterceptor拦截器
                .addInterceptor(new BaseInterceptor())
                .build();
    }

    public <T> T createApi(final Class<T> service) {
        return mRetrofit.create(service);
    }
}

这里在顺带说下OkHttp自带的拦截器功能。所谓拦截器,就是对发出的请求和返回的响应都可以进行拦截,并进行相应的处理,再把请求发送出去或者把响应返回给用户。比如有些时候,我们需要在每个请求中都添加一些公共参数,每次请求再去添加这些参数也可以,但是这样不太优雅,这时我们就可以为OkHttpClient配置一个拦截器,拦截每一个请求,并在请求中加上我们的公共参数,这样客户端发出的每一个请求都会带上公共参数;或者有时候需要在请求头中添加某些信息,比如机型、系统型号等等信息,每个请求都手动加也不太好,同样可以在拦截器中进行配置,把公共的头部信息加进去,然后再发送给服务端。至于具体的实现,OkHttp中内置了一个接口Interceptor,自定 义拦截器需要实现该接口,并重写其intercept方法。然后再配置到OkHttpClient中
即可。代码就一行:


在这里插入图片描述

主要是BaseInterceptor的实现。代码如下:

public class BaseInterceptor implements Interceptor {

    @NonNull
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        //POST请求
        if (request.method().equals("POST")) {
            FormBody formBody = null;
            FormBody.Builder bodyBuilder = new FormBody.Builder();
            if (request.body() instanceof FormBody) {
                formBody = (FormBody) request.body();
                //把原来的参数添加到新的构造器,(因为没找到直接添加,所以就new新的)
                for (int i = 0; i < formBody.size(); i++) {
                    bodyBuilder.add(formBody.name(i), formBody.value(i));
                }
                //添加公共参数
                formBody = bodyBuilder
                        .add("pubParam1", "1")
                        .add("pubParam2", "2")
                        .add("pubParam3", "3")
                        .build();

                //添加请求头
                request = request
                        .newBuilder()
                        .post(formBody)
                        .addHeader("Content-Type", "application/json;charset=UTF-8")
                        .addHeader("User-Agent", "android")
                        .build();
            }
            return chain.proceed(request);
        } else {
            //添加公共参数
            HttpUrl.Builder urlBuilder = request.url()
                    .newBuilder()
                    .addQueryParameter("pubParam1", "1")
                    .addQueryParameter("pubParam2", "2")
                    .addQueryParameter("pubParam3", "3");

            //添加请求头
            Request.Builder newBuilder = request.newBuilder()
                    .method(request.method(), request.body())
                    .url(urlBuilder.build())
                    .addHeader("Content-Type", "application/json;charset=UTF-8")
                    .addHeader("User-Agent", "android");

            return chain.proceed(newBuilder.build());
        }

    }

}

这里分了POST和GET等其它请求,POST和GET添加请求头和添加参数的代码不同,所以得判断请求的method。好吧 ,让我们来看下GET请求,通过Fiddler抓包工具抓到的请求:


在这里插入图片描述

公共参数拼接在url地址后面,请求头中放了两个字段Content-Type和User-Agent,和我们设置的值是一致的。再看下POST请求的结果,代码需要做稍许的修改


在这里插入图片描述
把GET改成POST,加一个@FormUrlEncoded的注解,参数为一个map,调用的地方传入一个空的map集合即可:

在这里插入图片描述

请求一次再看抓包的结果


在这里插入图片描述

POST请求和GET不同,公共参数在请求体中,请求头不变。同样也生效了。好吧,拦截器还有许多可以深挖的东西,网上也有许多很好的博客,各位看官想深入了解可以自行百度哈~

  • 创建BaseView。每个Activity都实现一个接口,该接口都继承自BaseView接口。BaseView中放一些每个Activity都会用到的功能,比如显示和隐藏加载框、Toast展示提示信息等。
public interface BaseView{
    /**
     * Show loading
     */
    void showLoading();

    /**
     * Hide loading
     */
    void hideLoading();

    /**
     * Show Msg
     */
    void showMsg(String msg);

     /**
     * 获取Lifecycle对象,用于Activity  onDestroy时取消观察者的订阅。
     */
    <R> BehaviorSubject<R> getLifeCycleSubject();
}
  • 建立BasePresenter基类。每个Activity对应一个Presenter,都继承自BasePresenter,mvp中的逻辑代码都放在此类中。Presenter中持有Activity实现接口的引用。所以Presenter可以调用Activity中的代码。
public abstract class BasePresenter<V extends BaseView> {
    protected V mView;

    public BasePresenter(V mView) {
        this.mView = mView;
    }
}

  • 封装BaseActivity
public abstract class BaseActivity<T extends BasePresenter> extends RxAppCompatActivity implements BaseView {
    //RxLifecycle对象,每个Activity 调用onDestroy时用来取消观察者的订阅。
    private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();
    //Presanter,继承自BasePresenter。
    protected T mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //构建该Activity的Presenter对象。
        mPresenter = createPresenter();
    }
    
    public abstract T createPresenter();

    @SuppressWarnings("unchecked")
    @Override
    public final BehaviorSubject getLifeCycleSubject() {
        return lifecycleSubject;
    }
}

代码应该挺好理解,主要就是Activity和Prensenter的相互调用,这两个分别充当mvp中的V和P。我们在BaseActivity的基础上写一个Demo Activity,再来解释要好一点。我们都知道mvp好是好,但是有一个问题就是会让整个项目的类变的很多。每写一个Activity都要一个Prensenter(继承自BasePrensenter)和一个View接口(继承自BaseView)。即每次都要额外写两个类 ,写多了也挺烦,然而又不能省略,所以这里把Presenter和View放到一个类中。我们称之为Contract类,至于为啥叫这个名字,我也是参考了别人的命名哈哈~

  1. 让我们看看Contract的代码
public class MainContract {
       /*
     * Activity实现的接口
     * */
    public interface IView extends BaseView {
         void doSomething();
    }

    public static class Prensenter extends BasePresenter<IView> {
        private API api;
        private Gson gson;

        public Prensenter(IView mView) {
            super(mView);
            api = RetrofitManager.getInstance().createApi(API.class);
            gson = new Gson();
        }

        public void getPublicAccountList() {

            api.getPublicAccountList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(RxLifecycle.bindUntilEvent(mView.getLifeCycleSubject(), ActivityEvent.DESTROY))
                    .doOnSubscribe(disposable -> mView.showLoading())
                    .doFinally(() -> mView.hideLoading())
                    .subscribe(new Observer<PublicAccountBean>() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onNext(PublicAccountBean publicAccountBean) {
                            //成功
                            mView.doSomething();
                            for (int i = 0; i < publicAccountBean.getData().size(); i++) {
                            Log.e("data----------", publicAccountBean.getData().get(i).getName());
                            }
                        }

                        @Override
                        public void onError(Throwable e) {
                        //失败
                        Log.e("error--------",e.getMessage());
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        }
    }
}

可以看到我们把View和Presenter放在了一个类中。Presenter中初始化了Api请求接口,请求的时候直接调用Api请求接口中的方法就行啦。返回一个Observable对象,然后直接用就行了。好吧我们再看一下Activity中的代码:

public class MainActivity extends BaseActivity<MainContract.Prensenter> implements MainContract.IView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mPresenter.getPublicAccountList();
    }

    @Override
    public MainContract.Prensenter createPresenter() {
        return new MainContract.Prensenter(this);
    }

    @Override
    public void showLoading() {

    }

    @Override
    public void hideLoading() {

    }

    @Override
    public void showMsg(String msg) {

    }

    @Override
    public void doSomething() {
        
    }
}

结果是一样的,这里就不贴图片了哈,可以看到Actvity实现了MainContract中的IView接口,而Presenter中又持有一个IView接口的变量,所以Presenter可以调用MainActivity中的代码,同样Activity也持有一个Presenter的变量,所以Activity可以和Presenter相互调用。好吧,我实在不知道怎么描述了,只可意会不可言传~

写到这,基本的框架已经搭建起来了,BaseActivity里面可以根据自己的需求抽取一些公共的方法。但还有一个点可以稍微优化下:

api.getPublicAccountList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(RxLifecycle.bindUntilEvent(mView.getLifeCycleSubject(), ActivityEvent.DESTROY))
                    .doOnSubscribe(disposable -> mView.showLoading())
                    .doFinally(() -> mView.hideLoading())
                    .subscribe(new Observer<PublicAccountBean>() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onNext(PublicAccountBean publicAccountBean) {

                        }

                        @Override
                        public void onError(Throwable e) {

                        }

                        @Override
                        public void onComplete() {

                        }
                    });

有没有觉得这个代码很长啊,Observer接口里面有四个方法需要重写,有时候我们不想要这么多方法,只想要一个success和一个error方法,怎么办呢?也简单,封装一个BaseObserver。代码如下:

public abstract class BaseObserver<T> implements Observer<T> {

    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(T t) {
        success(t);
    }

    @Override
    public void onError(Throwable e) {
        if (e instanceof NetException.ResponseException) {
            error((NetException.ResponseException) e);
        } else {
            onError(new NetException.ResponseException(e, NetException.ERROR.UNKNOWN));
        }
    }

    @Override
    public void onComplete() {
    }

    public abstract void success(T t);

    public abstract void error(NetException.ResponseException e);

里面定义了两个抽象方法,一个success;一个error方法,传入一个NetException(自定义的,代码待会贴出来)对象,BaseObserver实现Observer接口,这里是RxJava里面的Observer,不要写错了,实现其中的四个方法。并传入一个请求成功的泛型,在onNext方法中调用success方法,在onError中调用error方法。好吧,我们再看下MainConract调用:

public class MainContract {
    /*
     * Activity实现的接口
     * */
    public interface IView extends BaseView {
        void doSomething();
    }

    public static class Prensenter extends BasePresenter<IView> {
        private API api;
        private Gson gson;

        public Prensenter(IView mView) {
            super(mView);
            api = RetrofitManager.getInstance().createApi(API.class);
            gson = new Gson();
        }

        public void getPublicAccountList() {

            api.getPublicAccountList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(RxLifecycle.bindUntilEvent(mView.getLifeCycleSubject(), ActivityEvent.DESTROY))
                    .doOnSubscribe(disposable -> mView.showLoading())
                    .doFinally(() -> mView.hideLoading())
                    .subscribe(new BaseObserver<PublicAccountBean>() {
                        @Override
                        public void success(PublicAccountBean publicAccountBean) {
                            //成功
                        }

                        @Override
                        public void error(NetException.ResponseException e) {
                            //失败。
                        }
                    });
        }
    }
}

NetException代码:

public class NetException {
    private static final int UNAUTHORIZED = 401;
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;

    public static ResponseException handleException(Throwable e) {
        //转换成ResponseException,根据状态码判定错误信息
        ResponseException ex;
        if (e instanceof HttpException) {
            HttpException httpException = (HttpException) e;
            /**
             * 传入状态码,根据状态码判定错误信息
             */
            ex = new ResponseException(e, ERROR.HTTP_ERROR);
            switch (httpException.code()) {
                case UNAUTHORIZED:
                    ex.message = "未验证";
                    break;
                case FORBIDDEN:
                    ex.message = "服务禁止访问";
                    break;
                case NOT_FOUND:
                    ex.message = "服务不存在";
                    break;
                case REQUEST_TIMEOUT:
                    ex.message = "请求超时";
                    break;
                case GATEWAY_TIMEOUT:
                    ex.message = "网关超时";
                    break;
                case INTERNAL_SERVER_ERROR:
                    ex.message = "服务器内部错误";
                    break;
                case BAD_GATEWAY:
                    ex.message = "请求失败";
                    break;
                case SERVICE_UNAVAILABLE:
                    ex.message = "请求失败";
                    break;
                default:
                    ex.message = "请求失败";
                    break;
            }
            return ex;
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            ex = new ResponseException(e, ERROR.PARSE_ERROR);
            ex.message = "数据解析异常";
            return ex;
        } else if (e instanceof ConnectException) {
            ex = new ResponseException(e, ERROR.NETWORD_ERROR);
            ex.message = "请求失败";
            return ex;
        } else if (e instanceof javax.net.ssl.SSLHandshakeException) {
            ex = new ResponseException(e, ERROR.SSL_ERROR);
            ex.message = "证书验证失败";
            return ex;
        } else {
            ex = new ResponseException(e, ERROR.UNKNOWN);
            ex.message = "未知错误";
            return ex;
        }
    }

    /**
     * 约定异常
     */
    public static class ERROR {
        /**
         * 自定义异常
         */
        private static final int UNAUTHORIZED = 401;//请求用户进行身份验证
        private static final int UNREQUEST = 403;//服务器理解请求客户端的请求,但是拒绝执行此请求
        private static final int UNFINDSOURCE = 404;//服务器无法根据客户端的请求找到资源
        private static final int SEVERERROR = 500;//服务器内部错误,无法完成请求。
        /**
         * 协议出错
         */
        public static final int HTTP_ERROR = 1003;
        /**
         * 未知错误
         */
        public static final int UNKNOWN = 1000;
        /**
         * 解析错误
         */
        public static final int PARSE_ERROR = 1001;
        /**
         * 网络错误
         */
        public static final int NETWORD_ERROR = 1002;
        /**
         * 证书出错
         */
        public static final int SSL_ERROR = 1005;
    }


    /**
     * 统一异常类,便于处理
     */
    public static class ResponseException extends Exception {
        public int code;
        public String message;

        public ResponseException(Throwable throwable, int code) {
            super(throwable);
            this.code = code;
        }
    }
}

这里我只封装了错误信息和code,如果需要其它的信息,可以根据自己的需求添加。结果依旧是一样的哈。只不过Observer只重写了两个方法,另外两个方法可以选择性的重写。代码看起来稍微简洁那么一丢丢。呼,终于写完了,累死我了~


在这里插入图片描述

全部代码已经上传到GitHub,欢迎拍砖。代码传送门:RxMvp

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值