Retrofit2+Rxjava2之优雅的封装

来源:互联网 发布:软件项目管理目标 编辑:程序博客网 时间:2024/06/07 12:55

转载请说明出处

前言

      这篇文章主要是教大家如何封装Retrofit2+Rxjava2,所以实现原理不做过多的解释,如有不付,额(你咬我呀!), 

还有就是看这篇文章的同时,你一定要对 Retrofit2 和 Rxjava2 有所了解哦,不然懵逼了,我不负责哦,还有就是文章的开头用Retrofit2、和Rxjava2,是为了区分Retrofit1、和Rxjava1的版本为了后面更快的码字都用Retrofit、和Rxjava

 

亲,别着急,喝杯茶听我细细道来:

     我们看看使用Retrofit+Rxjava需要哪些依赖(使用Android studio的小伙伴跟着我的脚步eclipse的兄弟看着办)

    

    compile 'io.reactivex.rxjava2:rxjava:2.0.7'    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'    compile 'com.squareup.retrofit2:retrofit:2.1.0'    compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'    compile 'com.squareup.retrofit2:converter-gson:2.1.0'    compile 'com.squareup.okhttp3:okhttp:3.5.0'    compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'

     我们要知道Retrofit是基于OKhttp实现的,那么我们要写一个Retrofit工具,命名为RetrofitFactory

    首先我们要创建一个 OKHttpClient对象

             

                 OkHttpClient mOkHttpClient=new OkHttpClient.Builder()                .connectTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)//设置连接超时时间                .readTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)//设置读取超时时间                .writeTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)//设置写入超时时间                .addInterceptor(InterceptorUtil.HeaderInterceptor())//添加其他拦截器                .addInterceptor(InterceptorUtil.LogInterceptor())//添加日志拦截器                .build();

    为了代码的可读性我把拦截器提取到一个工具类为InterceptorUtil(不知道什么是拦截器的童鞋建议百度一下)里面有两个方法一个是答应日志拦截器的方法,一个是处理和拦截http请求的方法

package com.yr.example.http;import android.util.Log;import java.io.IOException;import okhttp3.Interceptor;import okhttp3.Request;import okhttp3.Response;import okhttp3.logging.HttpLoggingInterceptor;/** * @author yemao * @date 2017/4/9 * @description 拦截器工具类! */public class InterceptorUtil {    public static String TAG="----";    //日志拦截器    public static HttpLoggingInterceptor LogInterceptor(){        return new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {            @Override            public void log(String message) {                Log.w(TAG, "log: "+message );            }        }).setLevel(HttpLoggingInterceptor.Level.BODY);//设置打印数据的级别    }    public static Interceptor HeaderInterceptor(){      return   new Interceptor() {            @Override            public Response intercept(Chain chain) throws IOException {                Request mRequest=chain.request();                //在这里你可以做一些想做的事,比如token失效时,重新获取token                //或者添加header等等,PS我会在下一篇文章总写拦截token方法                return chain.proceed(mRequest);            }        };    }}


然后是创建一个Retrofit

        Retrofit mRetrofit=new Retrofit.Builder()                .baseUrl(HttpConfig.BASE_URL)//这个baseUrl是什么?比如一个接口为'http://baidu.com/xxx','http://baidu.com/'就可以为baseURL                .addConverterFactory(GsonConverterFactory.create())//添加gson转换器                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava转换器                .client(mOkHttpClient)//传入上面创建的OKHttpClient                .build();

ok创建好Retrofit我们需要创建一个接口APIFunction类与之关联

package com.yr.example.http;import com.yr.example.http.bean.BaseEntity;import com.yr.example.http.config.URLConfig;import io.reactivex.Observable;import retrofit2.http.GET;import retrofit2.http.Query;/** * @author yemao * @date 2017/4/9 * @description API接口! */public interface APIFunction {    }

终于可以看到我们完整的工具类RetrofitFactory了

     

package com.yr.example.http;import com.yr.example.http.config.HttpConfig;import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;import retrofit2.Retrofit;import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;import retrofit2.converter.gson.GsonConverterFactory;/** * @author yemao * @date 2017/4/9 * @description 写自己的代码, 让别人说去吧! */public class RetrofitFactory {    private static RetrofitFactory mRetrofitFactory;    private static  APIFunction mAPIFunction;    private RetrofitFactory(){        OkHttpClient mOkHttpClient=new OkHttpClient.Builder()                .connectTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)                .readTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)                .writeTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)                .addInterceptor(InterceptorUtil.HeaderInterceptor())                .addInterceptor(InterceptorUtil.LogInterceptor())//添加日志拦截器                .build();        Retrofit mRetrofit=new Retrofit.Builder()                .baseUrl(HttpConfig.BASE_URL)                .addConverterFactory(GsonConverterFactory.create())//添加gson转换器                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava转换器                .client(mOkHttpClient)                .build();        mAPIFunction=mRetrofit.create(APIFunction.class);    }    public static RetrofitFactory getInstence(){        if (mRetrofitFactory==null){            synchronized (RetrofitFactory.class) {                if (mRetrofitFactory == null)                    mRetrofitFactory = new RetrofitFactory();            }        }        return mRetrofitFactory;    }    public  APIFunction API(){        return mAPIFunction;    }}

    接下来我们就要开始接口了哦,回到我们上面的APIFunction接口模拟一个API接口getBaidu()因为上面我们已经对Retrofit和APIFunction进行关联了可以返回得到一个observable<Object>(终于轮到Rxjava出场了)

package com.yr.example.http;import com.yr.example.http.bean.BaseEntity;import com.yr.example.http.config.URLConfig;import io.reactivex.Observable;import retrofit2.http.GET;import retrofit2.http.Query;/** * @author yemao * @date 2017/4/9 * @description API接口! */public interface APIFunction {    @GET(URLConfig.baidu_url)    Observable<Object> getBaidu(@Query("wd")String name);}


额看到这里我们怎么让它返回一个对象实体,不能让它返回我们想要的实体类吗,答案是yes,OK那我们来封装一个BaseEntity

当然我这只是举例个例子,很有可能大家的返回参数不是按照下面的,(因实际情况做修改)

package com.yr.example.http.bean;/** * @author yemao * @date 2017/4/9 * @description 解析实体基类! */public class BaseEntity<T> {    private static int SUCCESS_CODE=42440;//成功的code    private int code;    private String msg;    private T data;    public boolean isSuccess(){        return getCode()==SUCCESS_CODE;    }    public int getCode() {        return code;    }    public void setCode(int code) {        this.code = code;    }    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }    public T getData() {        return data;    }    public void setData(T data) {        this.data = data;    }}

我们看看修改过后的接口是怎么样的

 @GET(URLConfig.baidu_url)    Observable<BaseEntity<Object>> getBaidu(@Query("wd")String name);

当然这是候的Object可以换为你想要的实体比如(前提是你要知道返回的数据类型我这只是打个比方)

package com.yr.example.http.bean;/** * @author yemao * @date 2017/4/9 * @description 写自己的代码, 让别人说去吧! */public class ABean {    private String name;    private String pwd;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPwd() {        return pwd;    }    public void setPwd(String pwd) {        this.pwd = pwd;    }}


把object替换为ABean

   @GET(URLConfig.baidu_url)    Observable<BaseEntity<ABean>> getBaidu(@Query("wd")String name);


OK这时候就可以跑通了让我们看看完整的请求 (observable(被观察者)和observer(观察者)相订阅)

 RetrofitFactory.getInstence().API()                .getBaidu("我是中国人")                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new Observer<BaseEntity<ABean>>() {                    @Override                    public void onSubscribe(Disposable d) {                                            }                    @Override                    public void onNext(BaseEntity<ABean> aBeanBaseEntity) {                    }                    @Override                    public void onError(Throwable e) {                    }                    @Override                    public void onComplete() {                    }                });

可以发现还有地方可以优化比如Observable线程的切换,以及Observer的封装,不废话了我们先封装一个BaseObserver

BaseObserver实现了Observer接口,然后添加了5个方法


onRequestStart 请求开始时调用

onRequestEnd 请求结束时调用

onFailure 请求失败时调用 

onSuccees  请求成功时调用

onCodeError 请求成功但code码错误时调用


然后完整的BaseObserve

package com.yr.example.http.base;import android.accounts.NetworkErrorException;import android.content.Context;import android.util.Log;import com.yr.example.http.bean.BaseEntity;import com.yr.example.widget.ProgressDialog;import java.net.ConnectException;import java.net.UnknownHostException;import java.util.concurrent.TimeoutException;import io.reactivex.Observer;import io.reactivex.disposables.Disposable;/** * @author yemao * @date 2017/4/9 * @description 写自己的代码, 让别人说去吧! */public abstract class BaseObserver<T> implements Observer<BaseEntity<T>> {    protected Context mContext;    public BaseObserver(Context cxt) {        this.mContext = cxt;    }    public BaseObserver() {    }    @Override    public void onSubscribe(Disposable d) {        onRequestStart();    }    @Override    public void onNext(BaseEntity<T> tBaseEntity) {        onRequestEnd();        if (tBaseEntity.isSuccess()) {            try {                onSuccees(tBaseEntity);            } catch (Exception e) {                e.printStackTrace();            }        } else {            try {                onCodeError(tBaseEntity);            } catch (Exception e) {                e.printStackTrace();            }        }    }    @Override    public void onError(Throwable e) {//        Log.w(TAG, "onError: ", );这里可以打印错误信息        onRequestEnd();        try {            if (e instanceof ConnectException                    || e instanceof TimeoutException                    || e instanceof NetworkErrorException                    || e instanceof UnknownHostException) {                onFailure(e, true);            } else {                onFailure(e, false);            }        } catch (Exception e1) {            e1.printStackTrace();        }    }    @Override    public void onComplete() {    }    /**     * 返回成功     *     * @param t     * @throws Exception     */    protected abstract void onSuccees(BaseEntity<T> t) throws Exception;    /**     * 返回成功了,但是code错误     *     * @param t     * @throws Exception     */    protected void onCodeError(BaseEntity<T> t) throws Exception {    }    /**     * 返回失败     *     * @param e     * @param isNetWorkError 是否是网络错误     * @throws Exception     */    protected abstract void onFailure(Throwable e, boolean isNetWorkError) throws Exception;    protected void onRequestStart() {    }    protected void onRequestEnd() {        closeProgressDialog();    }    public void showProgressDialog() {        ProgressDialog.show(mContext, false, "请稍后");    }    public void closeProgressDialog() {        ProgressDialog.cancle();    }}

然后我们看看完整的请求

   RetrofitFactory.getInstence().API()                .getBaidu("我是中国人")                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new BaseObserver<ABean>() {                    @Override                    protected void onSuccees(BaseEntity<ABean> t) throws Exception {                    }                    @Override                    protected void onFailure(Throwable e, boolean isNetWorkError) throws Exception {                    }                });

是不是少了许多代码,最后我们将线程切换提成一个方法,放在一个新建的baseActivity里面让所有activity都继承自它,就都可以拿到这个方法了

package com.yr.example.common;import android.support.v4.app.FragmentActivity;import io.reactivex.Observable;import io.reactivex.ObservableSource;import io.reactivex.ObservableTransformer;import io.reactivex.android.schedulers.AndroidSchedulers;import io.reactivex.schedulers.Schedulers;/** * @author yemao * @date 2017/4/9 * @description 写自己的代码, 让别人说去吧! */public class BaseActivity extends FragmentActivity {    public <T> ObservableTransformer<T,T> setThread(){       return new ObservableTransformer<T,T>() {            @Override            public ObservableSource<T>  apply(Observable<T>  upstream) {                return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());            }        };    }}



最后看看完成的请求

package com.yr.example;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import com.yr.example.common.BaseActivity;import com.yr.example.http.RetrofitFactory;import com.yr.example.http.base.BaseObserver;import com.yr.example.http.bean.ABean;import com.yr.example.http.bean.BaseEntity;import io.reactivex.Observer;import io.reactivex.android.schedulers.AndroidSchedulers;import io.reactivex.disposables.Disposable;import io.reactivex.schedulers.Schedulers;public class MainActivity extends BaseActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        getData();    }    public void getData() {        RetrofitFactory.getInstence().API()                .getBaidu("我是中国人")                .compose(this.<BaseEntity<ABean>>setThread())                .subscribe(new BaseObserver<ABean>() {                    @Override                    protected void onSuccees(BaseEntity<ABean> t) throws Exception {                    }                    @Override                    protected void onFailure(Throwable e, boolean isNetWorkError) throws Exception {                    }                });    }}

还有两个config类我就不贴了,没什么技术含量,随后我会在文章的结尾demo下载地址

那么到这里,封装基本上大功告成了,但是上面例子并不能成功解析,因为我调用的百度的搜索接口,返回的是XML,不过拿去真实的服务器请求是完全没有问题的哦

最后贴一下项目目录结构






GitHub项目地址:点击打开链接https://git.oschina.net/yrmao/retrofit2_rxjava2-android


















15 0
原创粉丝点击