转载请说明出处
前言
这篇文章主要是教大家如何封装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,不过拿去真实的服务器请求是完全没有问题的哦
最后贴一下项目目录结构
GitHub项目地址:点击打开链接https://git.oschina.net/yrmao/retrofit2_rxjava2-android