Retrofit2+Rxjava2之优雅的封装

转载请说明出处

前言

      这篇文章主要是教大家如何封装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(终于轮到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 getBaidu(@Query("wd")String name);
}
 
  

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

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

package com.yr.example.http.bean;

/**
 * @author yemao
 * @date 2017/4/9
 * @description 解析实体基类!
 */

public class BaseEntity {
    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> 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> getBaidu(@Query("wd")String name);


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

 RetrofitFactory.getInstence().API()
                .getBaidu("我是中国人")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        
                    }

                    @Override
                    public void onNext(BaseEntity 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 implements Observer> {
    protected Context mContext;

    public BaseObserver(Context cxt) {
        this.mContext = cxt;
    }

    public BaseObserver() {

    }

    @Override
    public void onSubscribe(Disposable d) {
        onRequestStart();

    }

    @Override
    public void onNext(BaseEntity 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) throws Exception;

    /**
     * 返回成功了,但是code错误
     *
     * @param t
     * @throws Exception
     */
    protected void onCodeError(BaseEntity 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() {
                    @Override
                    protected void onSuccees(BaseEntity 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  ObservableTransformer setThread(){
       return new ObservableTransformer() {
            @Override
            public ObservableSource  apply(Observable  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.>setThread())
                .subscribe(new BaseObserver() {
                    @Override
                    protected void onSuccees(BaseEntity t) throws Exception {

                    }

                    @Override
                    protected void onFailure(Throwable e, boolean isNetWorkError) throws Exception {

                    }
                });
    }
}

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

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

最后贴一下项目目录结构



Retrofit2+Rxjava2之优雅的封装_第1张图片


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


















你可能感兴趣的:(android)