前言
Retrofit
和RxJava
已经出来很久了,很多前辈写了很多不错的文章,在此不得不感谢这些前辈无私奉献的开源精神,能让我们站在巨人的肩膀上望得更远。
Retrofit:Retrofit是Square 公司开发的一款针对Android 网络请求的框架。
RxJava:RxJava 是一个链式调用的异步框架。
RxJava在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。
一言以辟之,就是让异步操作变得非常简单。
各自职责:Retrofit 负责请求的数据和请求的结果,使用接口的方式呈现,OkHttp 负责请求的过程,RxJava 负责异步,各种线程之间的切换。
RxJava
的使用参考-->给 Android 开发者的 RxJava 详解
Retrofit
的使用参考-->Android Retrofit 2.0使用
本文内容是基于Retrofit + RxJava
做的一些优雅的封装。参考了很多文章加入了一些自己的理解,请多指教。
先引入依赖
build.gradle
// Okhttp库
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'
// Retrofit库
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
//RxJava
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
在此之前,
先来聊聊简单使用,(优雅封装见下文)
1、先写一个接口Service
interface APIService {
@GET("user/login" )
Call<UserInfo> login(@Query("username") String username,@Query("password")String password);
}
2、获取Call执行网络请求
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
APIService service = retrofit.create(APIService.class);
Call<UserInfo> call = service.login("张晓宇", "is sb");
call.enqueue(new Callback<UserInfo>() {
@Override
public void onResponse(Call<UserInfo> call, Response<UserInfo> response) {
//请求成功
}
@Override
public void onFailure(Call<UserInfo> call, Throwable t) {
//请求失败
}
});
以上就是Retrofit的简单使用。但是实际项目中,我们肯定不会这么写,这样写完全不符合我们写代码的优雅性和简洁性。所以,我们要对它进行优雅的封装。
Retrofit+RxJava优雅的封装
1、请求实体类与返回实体类的封装
BaseRequestEntity.java
public class BaseRequestEntity <T>{
private HeaderEntity header;
private T data;
public HeaderEntity getHeader() {
return header;
}
public void setHeader(HeaderEntity header) {
this.header = header;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
BaseResponseEntity.java
public class BaseResponseEntity<T> {
private int errorCode;
private String errorMsg;
private T data;
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
2、请求接口服务类封装
ObservableAPI.java
/**
* 接口服务
**/
public interface ObservableAPI {
/**
* 登录
*/
@POST(URL.URL_LOGIN)
Observable<BaseResponseEntity<LoginResponseEntity>> login(@Body BaseRequestEntity<LoginRequestEntity> requestEntity);
}
3、ObservableManager封装(请求接口传参封装)
ObservableManager.java
public class ObservableManager {
private static class SingletonHolder {
static final ObservableManager INSTANCE = new ObservableManager();
}
public static ObservableManager getInstance() {
return ObservableManager.SingletonHolder.INSTANCE;
}
/**
* login
*/
public BaseRequestEntity<LoginRequestEntityl> getLoginRequestEntity() {
BaseRequestEntity<LoginRequestEntity> requestModel = new BaseRequestEntity<>();
requestModel.setHeader(HeaderUtils.setHeaderModel());
LoginRequestEntity loginRequestModel = new LoginRequestEntity();
requestModel.setData(loginRequestModel);
return requestModel;
}
}
4、Retrofit封装
RetrofitHandler.java
public class RetrofitHandler {
private static Retrofit mRetrofit;
private static OkHttpClient mOkHttpClient;
private static RetrofitHandler mRetrofitHandler;
private static ObservableAPI mObservableAPI;
private RetrofitHandler() {
initRetrofit();
}
public static synchronized RetrofitHandler getInstance() {
if (mRetrofitHandler == null) {
synchronized (RetrofitHandler.class) {
if (mRetrofitHandler == null) {
mRetrofitHandler = new RetrofitHandler();
}
}
}
return mRetrofitHandler;
}
/**
* 获取 Retrofit
*/
private void initRetrofit() {
initOkHttpClient();
mRetrofit = new Retrofit.Builder()
.baseUrl(URL.BASE_URL)
//JSON转换器,使用Gson来转换
.addConverterFactory(GsonConverterFactory.create())
//RxJava适配器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(mOkHttpClient)
.build();
mObservableAPI = mRetrofit.create(ObservableAPI.class);
}
/**
* 单例模式获取 OkHttpClient
*/
private static void initOkHttpClient() {
if (mOkHttpClient == null) {
synchronized (RetrofitHandler.class) {
if (mOkHttpClient == null) {
// 指定缓存路径,缓存大小100Mb
Cache cache = new Cache(new File(HttpConfig.DIR_CACHE_FILE, "HttpCache"),
1024 * 1024 * 100);
mOkHttpClient = new OkHttpClient.Builder()
//设置连接超时时间
.connectTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
//设置读取超时时间
.readTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
//设置写入超时时间
.writeTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
//默认重试一次
.retryOnConnectionFailure(true)
//添加请求头拦截器
.addInterceptor(InterceptorHelper.getHeaderInterceptor())
//添加日志拦截器
.addInterceptor(InterceptorHelper.getLogInterceptor())
//添加缓存拦截器
.addInterceptor(InterceptorHelper.getCacheInterceptor())
//添加重试拦截器
.addInterceptor(InterceptorHelper.getRetryInterceptor())
// 信任Https,忽略Https证书验证
// https认证,如果要使用https且为自定义证书 可以去掉这两行注释,并自行配制证书。
.sslSocketFactory(SSLSocketTrust.getSSLSocketFactory())
.hostnameVerifier(SSLSocketTrust.getHostnameVerifier())
//缓存
.cache(cache)
.build();
}
}
}
}
/**
* 对外提供调用 API的接口
*
* @return
*/
public ObservableAPI getAPIService() {
return mObservableAPI;
}
}
5、拦截器封装(请求头拦截器、日志拦截器、缓存拦截器、重试拦截器等)
InterceptorHelper.java
/**
* @author wy
* @description 拦截器工具类
*/
public class InterceptorHelper {
public static String TAG = "Interceptor";
/**
* 日志拦截器
*/
public static HttpLoggingInterceptor getLogInterceptor() {
return new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.w(TAG, "LogInterceptor---------: " + message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY);//设置打印数据的级别
}
/**
* 缓存拦截器
*
* @return
*/
public static Interceptor getCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//CONTEXT不能为空
if (!NetworkUtils.isConnected(PalApplication.getInstance().getApplicationContext())) {
int maxStale = 4 * 7 * 24 * 60; // 离线时缓存保存4周,单位:秒
CacheControl tempCacheControl = new CacheControl.Builder()
.onlyIfCached()
.maxStale(maxStale, TimeUnit.SECONDS)
.build();
request = request.newBuilder()
.cacheControl(tempCacheControl)
.build();
}
return chain.proceed(request);
}
};
}
/**
* 重试拦截器
*
* @return
*/
public static Interceptor getRetryInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
int maxRetry = 10;//最大重试次数
int retryNum = 5;//假如设置为3次重试的话,则最大可能请求4次(默认1次+3次重试)
Request request = chain.request();
Response response = chain.proceed(request);
while (!response.isSuccessful() && retryNum < maxRetry) {
retryNum++;
response = chain.proceed(request);
}
return response;
}
};
}
/**
* 请求头拦截器
*
* @return
*/
public static Interceptor getHeaderInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
//在这里你可以做一些想做的事,比如token失效时,重新获取token
//或者添加header等等
Request originalRequest = chain.request();
if (null == originalRequest.body()) {
return chain.proceed(originalRequest);
}
Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")
.header("User-Agent", "OkHttp Headers.java")
.addHeader("Accept", "application/json; q=0.5")
.addHeader("Accept", "application/vnd.github.v3+json")
.addHeader("Accept-Encoding", "identity")
// .addHeader(Constants.WEB_TOKEN, webi_token)
.build();
Response proceed = chain.proceed(compressedRequest);
return proceed;
}
};
}
}
6、BaseObserver封装(请求失败、网络异常、接口错误、加载窗口等处理)
BaseObserver.java
public abstract class BaseObserver<T> implements Observer<BaseResponseEntity<T>> {
protected Context mContext;
public BaseObserver() {
}
public BaseObserver(Context cxt) {
this.mContext = cxt;
}
@Override
public void onSubscribe(Disposable d) {
onRequestStart();
}
@Override
public void onNext(BaseResponseEntity<T> tBaseEntity) {
onRequestEnd();
String message_common = "Oops, something went wrong. Please try again.";
if (tBaseEntity.getErrorCode()==0) {//成功
try {
onSuccess(tBaseEntity);
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
if (!CommonUtils.isEmptyOrNull(tBaseEntity.getErrorMsg())) {
onFailure(tBaseEntity.getErrorMsg());
} else {
onFailure(message_common);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onError(Throwable e) {
onRequestEnd();
String message_common = "Oops, something went wrong. Please try again.";
String msg_timeout = "Oops, connection timeout, please try again later";
try {
if (e instanceof ConnectException
|| e instanceof TimeoutException
|| e instanceof NetworkErrorException
|| e instanceof UnknownHostException) {
onFailure(msg_timeout);
} else {
onFailure(message_common);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
@Override
public void onComplete() {
}
/**
* 返回成功
*
* @param tBaseEntity
*/
protected abstract void onSuccess(BaseResponseEntity<T> tBaseEntity);
/**
* 返回失败
*
* @param errorMessage
*/
protected abstract void onFailure(String errorMessage);
/**
* 请求开始
*/
protected void onRequestStart() {
showProgressDialog();
}
/**
* 请求结束
*/
protected void onRequestEnd() {
closeProgressDialog();
}
/**
* 加载弹窗
*/
public void showProgressDialog() {
}
/**
* 关闭加载弹窗
*/
public void closeProgressDialog() {
}
}
7、调度类封装
RxTransformerHelper.java
/**
* 调度类
*/
public class RxTransformerHelper {
public static <T> ObservableTransformer<T, T> observableIO2Main(final Context context) {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
};
}
}
8、使用方式
private void login() {
RetrofitHandler.getInstance().getAPIService()
.login(ObservableManager.getInstance().getLoginRequestEntity())
.compose(RxTransformerHelper.<BaseResponseEntity<LoginResponseEntity>>observableIO2Main(this))
.subscribe(new BaseObserver<LoginResponseEntity>() {
@Override
protected void onSuccess(BaseResponseEntity<LoginResponseEntity> responseEntity) {
showSuccessDialog("Success");
}
@Override
protected void onFailure(String errorMessage) {
showErrorDialog(errorMessage);
}
});
}