本篇文章主要介绍Rxjava与Retrofit结合使用,对Rxjava和Retrofit不熟悉的能够去看我以前的两篇介绍java
public interface GetRequest_Interface {
@POST("/app/auth/school/list")
Observable<School> postSchool(@Body RequestBody route);//根据学校名获取学校
}
复制代码
GetRequest_Interface request = new Retrofit.Builder()
.baseUrl(API.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build().create(GetRequest_Interface.class);
复制代码
这里以请求体为Json 字符串为准git
HashMap<String, Object> map = new HashMap<>();
map.put(key, value);
Gson gson=new Gson();
String strEntity = gson.toJson(map);
KLog.d("22222222RequestBody"+strEntity);
RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json;charset=UTF-8"),strEntity);
复制代码
Observable<School> observable = request.postSchool(body);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<School>() {
@Override
public void onSubscribe(Disposable d) {
//此处作一些请求开始时的初始化事件,例如弹出一个dialog
}
@Override
public void onNext(School school) {
//此到处理请求成功业务(code == 200 )
}
@Override
public void onError(Throwable e) {
//此到处理请求失败业务(code != 200 )
}
@Override
public void onComplete() {
//请求完成处理业务,关闭请求队列,关闭dialog等
}
});
复制代码
至此,Rxjava 与 Retrofit 结合基本使用就结束了,基于以上就能够愉快的完成网络请求工做了,是否是很方便简洁.编程
固然了,对于咱们的业务来讲,不可能只有一次网络请求,基本到处都须要进去网络请求,并且也不可能如上面同样,如此简单. 通常咱们的业务中都须要配置一些其余的参数信息,若是每一次网络请求都像上面那样写的话,固然是能够的,可是你的代码就太low了,也不符合编程规范.json
因此基于你会熟练的使用了的前提下,咱们就须要将以上代码进行简单封装.segmentfault
关于封装我想多说一句api
对于封装,不少人都认为封装就是使代码足够简洁,逻辑足够清晰,符合开闭原则等,的确是这样的,可是须要使状况而定,若是你写的代码是服务广大人群,也就是开源项目,那就要考虑不少因素,作到足够开放.数组
但若是只是用到本身的项目里,那咱们必需要明确一点,那就是定制化的前提是符合本身业务的需求,而不要过于封装.因此也就有为何咱们经常须要对别人的开源框架作二次封装,就是这个道理,没有最好的封装,只有最合适的封装.安全
public interface API {
//此处存放全部的BaseUrl
String BASE_URL = "http://xx.xxx.xx.225:8080"; //核心后台API
String BASE_SCHOOL_URL = "http://xx.xxx.xx.225:8081"; //学校API
}
复制代码
public interface GetRequest_Interface {
/*-------------------------------------全部网络请求 API-------------------------------------------------------*/
@POST("/app/auth/captcha")
Observable<Phone> postPhone(@Body RequestBody route); //获取验证码
@POST("/app/auth/login")
Observable<RegistLogin> postRegist(@Body RequestBody route);//登陆注册
}
复制代码
根据本身业务需求初始化OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS) //l 链接超时时间
.writeTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS) //读写超时
.readTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS) //读取超时
.retryOnConnectionFailure(true) //失败重连
.addNetworkInterceptor(tokenInterceptor) //添加网络拦截器
.addInterceptor(tokenRespInterceptor)
//.authenticator(authenticator) //受权认证
.build();
复制代码
这里须要用到OkHttp3的拦截器相关内容,不熟悉的能够先去了解bash
Interceptor tokenInterceptor = new Interceptor() { //全局拦截器,
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();//获取原始请求
Request.Builder requestBuilder = originalRequest.newBuilder() //创建新的请求
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json; charset=utf-8")
.removeHeader("User-Agent")
.addHeader("User-Agent",BaseUtils.getUserAgent())
.method(originalRequest.method(),originalRequest.body());
return chain.proceed(requestBuilder.build()); //从新请求
复制代码
Interceptor tokenInterceptor = new Interceptor() { //全局拦截器,往请求头部添加 token 字段,实现了全局添加 token
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();//获取原始请求
Request.Builder requestBuilder = originalRequest.newBuilder() //创建新的请求
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json; charset=utf-8")
.removeHeader("User-Agent")
.addHeader("User-Agent",BaseUtils.getUserAgent())
.method(originalRequest.method(),originalRequest.body());
// Log.e("----------------",originalRequest.body().toString());
Request tokenRequest = null; //带有token的请求
if (StringUtils.isEmpty(App.mmkv.decodeString(BaseConfig.TOKEN,null))){
return chain.proceed(requestBuilder.build());
}
tokenRequest = requestBuilder
.header("Authorization","Bearer "+App.mmkv.decodeString(BaseConfig.TOKEN,null))
.build();
return chain.proceed(tokenRequest);
}
};
复制代码
这里使用了腾讯的MMKV框架进去本地存储Token,由于咱们一开始是没有拿到Token的,因此须要进行动态添加网络
在进行网络交互的时候,服务端签发的Token是有时效性的并且通常比较短,过了有效期就须要从新请求,而这个过程咱们不能让用户察觉到,因此须要实现用户无感知的状况下刷新请求新的Token.
Interceptor tokenRespInterceptor = new Interceptor() { //拦截返回体 判断token是否过时.过时重写拉取新的token
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
// KLog.d( response.body().string());
if (isTokenExpired(response)){
KLog.d( "自动刷新Token,而后从新请求数据");
//同步请求方式,获取最新的Token
String newToken = getNewToken();
if (newToken != null){
//使用新的Token,建立新的请求
Request newRequest = chain.request()
.newBuilder()
.header("Authorization", "Bearer " + newToken)
.build();
//从新请求
return chain.proceed(newRequest);
}
}
return response.newBuilder().body(ResponseBody.create(MediaType.parse("UTF-8"),body)).build();
}
};
复制代码
这里须要根据服务端约定好的过时规则进去判断,这里简单示范一下
/**
* 根据Response,判断Token是否失效
*
* @param response
* @return
*/
private boolean isTokenExpired(Response response) {
try {
body = response.body().string();
JSONObject object = new JSONObject(body);
message = object.getString("Message");
code = object.getInt("Code");
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
if ("Token is expired".equals(message)&& code == 1) {
return true;
}
return false;
}
复制代码
获取新的Token
/**
* 同步请求方式,获取最新的Token
*
* @return
*/
private String getNewToken() {
// 经过获取token的接口,同步请求接口
GetRequest_Interface request = new Retrofit.Builder()
.baseUrl(API.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build().create(GetRequest_Interface.class);
// KLog.e(Remember.getString("refresh_token",null));
RequestBody body = BaseUtils.convertJson(BaseUtils.paramsMap("refresh_token",App.mmkv.decodeString(BaseConfig.REFRESH_TOKEN,null)));
Call<RefreshToken> call = request.postRefreshToken(body);
try {
response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
KLog.e(response.body().getCode()+response.body().getMessage());
if (response.code() == 200 &&response.body().getCode() ==0){
newToken = response.body().getData().getToken();
KLog.e("---------------"+newToken);
App.mmkv.encode(BaseConfig.TOKEN,newToken);
App.mmkv.encode(BaseConfig.SCHOOL_TOKEN,response.body().getData().getSchool_token());
App.mmkv.encode(BaseConfig.EXPIRE_IN,response.body().getData().getExpire_in());
}
return newToken;
}
复制代码
retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(API.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
复制代码
至此,关于网络请求的相关参数信息就基本配置完成
将上述配置步骤进行封装
/**
* Created by darryrzhong
*
*
* 统一的Retrofit入口
*/
public class RetrofitHelper {
private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s
private static final int DEFAULT_READ_TIME_OUT = 10;
private final Retrofit retrofit;
private String body;
private retrofit2.Response<RefreshToken> response;
private String newToken;
private String message;
private int code;
private RetrofitHelper(){
Interceptor tokenInterceptor = new Interceptor() { //全局拦截器,往请求头部添加 token 字段,实现了全局添加 token
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();//获取原始请求
Request.Builder requestBuilder = originalRequest.newBuilder() //创建新的请求
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json; charset=utf-8")
.removeHeader("User-Agent")
.addHeader("User-Agent",BaseUtils.getUserAgent())
.method(originalRequest.method(),originalRequest.body());
// Log.e("----------------",originalRequest.body().toString());
Request tokenRequest = null; //带有token的请求
if (StringUtils.isEmpty(App.mmkv.decodeString(BaseConfig.TOKEN,null))){
return chain.proceed(requestBuilder.build());
}
tokenRequest = requestBuilder
.header("Authorization","Bearer "+App.mmkv.decodeString(BaseConfig.TOKEN,null))
.build();
return chain.proceed(tokenRequest);
}
};
Interceptor tokenRespInterceptor = new Interceptor() { //拦截返回体 判断token是否过时.过时重写拉取新的token
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
// KLog.d( response.body().string());
if (isTokenExpired(response)){
KLog.d( "自动刷新Token,而后从新请求数据");
//同步请求方式,获取最新的Token
String newToken = getNewToken();
if (newToken != null){
//使用新的Token,建立新的请求
Request newRequest = chain.request()
.newBuilder()
.header("Authorization", "Bearer " + newToken)
.build();
//从新请求
return chain.proceed(newRequest);
}
}
return response.newBuilder().body(ResponseBody.create(MediaType.parse("UTF-8"),body)).build();
}
};
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS) //l 链接超时时间
.writeTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS) //读写超时
.readTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS) //读取超时
.retryOnConnectionFailure(true) //失败重连
.addNetworkInterceptor(tokenInterceptor) //添加网络拦截器
.addInterceptor(tokenRespInterceptor)
//.authenticator(authenticator) //受权认证
.build();
retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(API.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
/**
* 同步请求方式,获取最新的Token
*
* @return
*/
private String getNewToken() {
// 经过获取token的接口,同步请求接口
GetRequest_Interface request = new Retrofit.Builder()
.baseUrl(API.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build().create(GetRequest_Interface.class);
RequestBody body = BaseUtils.convertJson(BaseUtils.paramsMap("refresh_token",App.mmkv.decodeString(BaseConfig.REFRESH_TOKEN,null)));
Call<RefreshToken> call = request.postRefreshToken(body);
try {
response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
KLog.e(response.body().getCode()+response.body().getMessage());
if (response.code() == 200 &&response.body().getCode() ==0){
newToken = response.body().getData().getToken();
KLog.e("---------------"+newToken);
App.mmkv.encode(BaseConfig.TOKEN,newToken);
App.mmkv.encode(BaseConfig.SCHOOL_TOKEN,response.body().getData().getSchool_token());
App.mmkv.encode(BaseConfig.EXPIRE_IN,response.body().getData().getExpire_in());
}
return newToken;
}
/**
* 根据Response,判断Token是否失效
*
* @param response
* @return
*/
private boolean isTokenExpired(Response response) {
try {
body = response.body().string();
JSONObject object = new JSONObject(body);
message = object.getString("Message");
code = object.getInt("Code");
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
if ("Token is expired".equals(message)&& code == 1) {
return true;
}
return false;
}
private static class SingletonHolder{
private static final RetrofitHelper INSTANCE = new RetrofitHelper();
}
/**
* 获取RetrofitServiceManager
* @return
*/
public static RetrofitHelper getInstance(){
return SingletonHolder.INSTANCE;
}
/**
* 获取对应的Service
* @param service Service 的 class
* @param <T>
* @return
*/
public <T> T create(Class<T> service){
return retrofit.create(service);
}
}
复制代码
若是业务中有多个BaseUrl的话,能够直接写个方法暴露出去就行了.
public interface ResponseCallBack<T> {
void onSuccess(T t);
void onFault(String errorMsg);
}
复制代码
public interface ProgressListener {
void startProgress();
void cancelProgress();
}
复制代码
建立BaseObserver,在回调中进行业务处理
public class BaseObserver<T> implements Observer<T> {
private ResponseCallBack responseCallBack;
private ProgressListener progressListener;
private Disposable disposable;
public BaseObserver(ResponseCallBack responseCallBack,ProgressListener progressListener){
this.responseCallBack = responseCallBack;
this.progressListener = progressListener;
}
}
复制代码
在 onSubscribe () 方法中进行请求开始时的初始化操做
@Override
public void onSubscribe(Disposable d) {
this.disposable = d;
if (progressListener != null){
progressListener.startProgress();
}
}
复制代码
在 onNext () 方法中处理请求成功业务
@Override
public void onNext(T t) {
responseCallBack.onSuccess(t);
}
复制代码
在onError () 方法中统一处理请求失败信息
@Override
public void onError(Throwable e) {
KLog.d(e.getMessage());
try {
if (e instanceof SocketTimeoutException) {//请求超时
responseCallBack.onFault("请求超时,请稍后再试");
} else if (e instanceof ConnectException) {//网络链接超时
responseCallBack.onFault("网络链接超时,请检查网络状态");
} else if (e instanceof SSLHandshakeException) {//安全证书异常
responseCallBack.onFault("安全证书异常");
} else if (e instanceof HttpException) {//请求的地址不存在
int code = ((HttpException) e).code();
if (code == 504) {
responseCallBack.onFault("网络异常,请检查您的网络状态");
} else if (code == 404) {
responseCallBack.onFault("请求的地址不存在");
} else {
responseCallBack.onFault("请求失败");
}
} else if (e instanceof UnknownHostException) {//域名解析失败
responseCallBack.onFault("域名解析失败");
} else {
responseCallBack.onFault("error:" + e.getMessage());
}
} catch (Exception e2) {
e2.printStackTrace();
} finally {
Log.e("OnSuccessAndFaultSub", "error:" + e.getMessage());
if (disposable !=null && !disposable.isDisposed()){ //事件完成取消订阅
disposable.dispose();
}
if (progressListener!=null){
progressListener.cancelProgress();
}
}
}
复制代码
在 onComplete () 中处理请求成功结束后的业务
@Override
public void onComplete() {
if (disposable !=null && !disposable.isDisposed()){ //事件完成取消订阅
disposable.dispose();
}
if (progressListener!=null){
progressListener.cancelProgress();
}
}
复制代码
代码以下:
/**
* Created by darryrzhong
*
*/
public class BaseObserver<T> implements Observer<T> {
private ResponseCallBack responseCallBack;
private ProgressListener progressListener;
private Disposable disposable;
public BaseObserver(ResponseCallBack responseCallBack,ProgressListener progressListener){
this.responseCallBack = responseCallBack;
this.progressListener = progressListener;
}
@Override
public void onSubscribe(Disposable d) {
this.disposable = d;
if (progressListener != null){
progressListener.startProgress();
}
}
@Override
public void onNext(T t) {
responseCallBack.onSuccess(t);
}
@Override
public void onError(Throwable e) {
KLog.d(e.getMessage());
try {
if (e instanceof SocketTimeoutException) {//请求超时
responseCallBack.onFault("请求超时,请稍后再试");
} else if (e instanceof ConnectException) {//网络链接超时
responseCallBack.onFault("网络链接超时,请检查网络状态");
} else if (e instanceof SSLHandshakeException) {//安全证书异常
responseCallBack.onFault("安全证书异常");
} else if (e instanceof HttpException) {//请求的地址不存在
int code = ((HttpException) e).code();
if (code == 504) {
responseCallBack.onFault("网络异常,请检查您的网络状态");
} else if (code == 404) {
responseCallBack.onFault("请求的地址不存在");
} else {
responseCallBack.onFault("请求失败");
}
} else if (e instanceof UnknownHostException) {//域名解析失败
responseCallBack.onFault("域名解析失败");
} else {
responseCallBack.onFault("error:" + e.getMessage());
}
} catch (Exception e2) {
e2.printStackTrace();
} finally {
Log.e("OnSuccessAndFaultSub", "error:" + e.getMessage());
if (disposable !=null && !disposable.isDisposed()){ //事件完成取消订阅
disposable.dispose();
}
if (progressListener!=null){
progressListener.cancelProgress();
}
}
}
@Override
public void onComplete() {
if (disposable !=null && !disposable.isDisposed()){ //事件完成取消订阅
disposable.dispose();
}
if (progressListener!=null){
progressListener.cancelProgress();
}
}
}
复制代码
至此,统一处理结果的BaseObserver封装完毕
这里根据服务端接收数据不一样而有不一样方式,想要了解更多传参方式,能够自行去了解Retrofit的注解,这里只介绍向服务端传递Json数据.
返回体:
{
"Code": 0,
"Data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC*********",
"refresh_token": "c9ced011-***************************",
"expire_in": 1560330991,
"student_id": 33
},
"Message": "登陆成功"
}
请求体:
{"phone":"13145214436","id":"12345"}
复制代码
返回体的数据解析就不说了,说说请求体怎么传递
首先咱们把最外面的{ } json 对象当作是一个 map 对象,这样是否是一会儿就知道怎么转化了,对的,就是你想的那样.
HashMap<String, Object> map = new HashMap<>();
map.put("phone", "13145214436");
map.put("id", "12345");
复制代码
而后把map对象转化成json字符串,传给服务端就好了
Gson gson=new Gson();
String strEntity = gson.toJson(map);
RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json;charset=UTF-8"),strEntity);
复制代码
至于更复杂的请求体也是同样的作法
{
"school_id":1,
"student_id":23,
"start_time":"2019-05-10 15:04:05",
"end_time":"2019-06-10 15:04:05",
"points": [
{
"longitude": 0,
"latitude": 0
},
{
"longitude": 0,
"latitude": 0
},
{
"longitude": 0,
"latitude": 0
},
{
"longitude": 0,
"latitude": 0
}
]
}
复制代码
上面的请求体中有个json数组,数组里面又嵌套了json对象,仍是同样的作法 把json数组当作是一个list,对的,有和上面同样的套路了是否是很简单,
这里以登陆业务作个简单示范
GetRequest_Interface request = RetrofitHelper.getInstance().create(GetRequest_Interface.class); //request请求入口
HashMap<String,Object> params = new HashMap();
params.put("phone",phone);
params.put("id",id);
RequestBody body = BaseUtils.convertJson(params);
Observable<RegistLogin> observable= request.postRegist(body);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver<RegistLogin>(new ResponseCallBack<RegistLogin>() {
@Override
public void onSuccess(RegistLogin registLogin) {
//此到处理 code == 200
}
@Override
public void onFault(String errorMsg) {
BaseUtils.showToast(mContext,errorMsg);
}
}, new ProgressListener() {
@Override
public void startProgress() {
dialog = BaseUtils.showSpotsDialog(mContext,"登陆中");
dialog.show();
}
@Override
public void cancelProgress() {
dialog.dismiss();
}
}));
复制代码
这样一来,是否是代码明了简洁,代码质量明显提升了一个层次
至此,Rxjava 和 Retrofit 结合使用 与封装就基本完成了,再次说明一下,没有最完美的封装,只有最适合本身业务的封装,因此,若是须要请进行本身的业务定制,这里只提供思路.
欢迎关注做者darryrzhong,更多干货等你来拿哟.
更多精彩文章请关注