這篇文章主要闡述在實際開發中如何封裝我們自己的網絡通信框架,網絡框架需提供請求日誌、失敗重試、異步請求等功能,如果你想了解這些,那看這篇文章就對了。如果你對Retrofit的使用還不瞭解,那你可以看之前一片文章:android 網絡框架(一)之Retrofit使用詳解。廢話不多說,下面我們進入正題。
一、引入SDK
//rxjava
api 'io.reactivex.rxjava2:rxjava:2.0.7'
api 'io.reactivex.rxjava2:rxandroid:2.0.1'
//retrofit
api 'com.squareup.retrofit2:retrofit:2.1.0'
//rxjava轉化
api 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
//請求返回轉換
api 'com.squareup.retrofit2:converter-scalars:2.0.2'
//okhttp
api 'com.squareup.okhttp3:okhttp:3.5.0'
//日誌
api 'com.squareup.okhttp3:logging-interceptor:3.6.0'
其實真正進行網絡請求的是OkHttp,Retrofit只是進行接口呈現,而RxJava負責異步請求。
二、BaseRetrofit封裝
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class BaseRetrofit<T> implements RetrofitWrapper<T> {
private static final String TAG = "BaseRetrofit";
private String url;
private Retrofit retrofit;
private Class<T> tClass;
private T service;
public BaseRetrofit(Class<T> tClass, String url){
this.tClass = tClass;
this.url = url;
initRetrofit(tClass);
}
@Override
public void initRetrofit(Class<T> tClass) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.readTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.writeTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor()) //加入日誌攔截
.retryOnConnectionFailure(true) //失敗重試
.build();
if (!url.endsWith("/")){
url += "/";
}
//創建retrofit實例
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) //返回轉換爲json格式
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //rxjava轉化
.baseUrl(url)
.build();
//創建請求接口實例
service = retrofit.create(tClass);
}
@Override
public T getService() {
if (null == service){
service = retrofit.create(tClass);
}
return service;
}
}
這樣封裝的好處是可以根據不同的api接口和請求地址創建不同的請求接口實例,另如果想返回格式爲字符串,可以這樣創建retrofit實例:
retrofit = new Retrofit.Builder()
.baseUrl(mUrl)
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxJava轉化器
.client(okHttpClient)
.build();
從上面的封裝我們知道,可以定義日誌攔截器來定製網絡請求日誌
import android.util.Log;
import com.example.practice.JsonUtil;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class LoggingInterceptor implements Interceptor {
private static final String TAG = "OkHttp";
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//請求時間
long requestTime = System.nanoTime();
//打印請求日誌
Log.d(TAG, "--> POST " + request.url()
+ "\nconnection:" + chain.connection()
+ "\n" + request.headers()
+ "\n --> END POST");
Response response = chain.proceed(request);
//響應時間
long responseTime = System.nanoTime();
MediaType mediaType = response.body().contentType();
String content = response.body().string();
if ((content.startsWith("{") && content.endsWith("}"))
|| (content.startsWith("[") && content.endsWith("]"))) {
content = JsonUtil.formatJson(content);
}
//記錄一次請求響應數據
Log.d(TAG, "<-- " + response.code()
+ " " + response.request().url()
+ "\n" + response.headers()
+ "\nconsumed time:" + (responseTime - requestTime) / 1e6d + "ms\n"
+ content + "\n<-- END HTTP");
response = response.newBuilder()
.body(ResponseBody.create(mediaType,content))
.build();
return response;
}
}
另外還可以設置重試機制
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;
public class RetryFunction implements Function<Observable<Throwable>, ObservableSource<?>> {
private int retryDelaySeconds;//延遲重試的時間
private int retryCount;//記錄當前重試次數
private int retryCountMax;//最大重試次數
public RetryFunction(int retryDelaySeconds, int retryCountMax) {
this.retryDelaySeconds = retryDelaySeconds;
this.retryCountMax = retryCountMax;
}
@Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Throwable throwable) throws Exception {
//如果失敗的原因是UnknownHostException(DNS解析失敗,當前無網絡),則沒必要重試,直接回調error結束請求即可
if (throwable instanceof UnknownHostException) {
return Observable.error(throwable);
}
//沒超過最大重試次數的話則進行重試
if (++retryCount <= retryCountMax) {
//延遲retryDelaySeconds後開始重試
return Observable.timer(retryDelaySeconds, TimeUnit.SECONDS);
}
return Observable.error(throwable);
}
});
}
}
三、定義api接口類
import com.example.practice.UserBean;
import io.reactivex.Observable;
import retrofit2.http.POST;
public interface RetrofitService {
/**
* 獲取用戶信息
* @param json
* @return
*/
@POST("user/getUserInfo")
Observable<ResponseBean> getUserInfo(String json);
}
四、定義Observer觀察者監聽網絡請求返回
import android.content.Context;
import android.util.Log;
import com.example.practice.ResponseBean;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
public abstract class BaseObserver implements Observer<ResponseBean> {
private static final String TAG = "BaseObserver";
private Context mContext;
public BaseObserver(Context context){
mContext = context;
}
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBean responseBean) {
try {
if (1000 == responseBean.getCode()){
onSuccess(responseBean.getData());
}else {
onCodeError(responseBean.getMsg());
}
}catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError:" + e.getMessage());
try {
onFailure(e);
}catch (Exception e1){
e1.printStackTrace();
}
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
/**
* 成功回調
* @param o
* @throws Exception
*/
protected abstract void onSuccess(Object o) throws Exception;
/**
* 返回異常
* @param msg
* @throws Exception
*/
protected abstract void onCodeError(String msg) throws Exception;
/**
* 請求失敗
* @param e
* @throws Exception
*/
protected abstract void onFailure(Throwable e) throws Exception;
}
五、發送網絡請求
BusinessRetrofit.getInstance().getService()
.getUserInfo("")
.compose(ThreadTransform.<ResponseBean>setThread())
.subscribe(new BaseObserver(this) {
@Override
protected void onSuccess(Object o) throws Exception {
}
@Override
protected void onCodeError(String msg) throws Exception {
}
@Override
protected void onFailure(Throwable e) throws Exception {
}
});
其中ThreadTransform用於控制線程轉化:子線線程與主線程轉化,以及設置重試機制
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class ThreadTransform {
public static <T> ObservableTransformer<T, T> setThread(){
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(io.reactivex.Observable<T> upstream) {
return upstream.subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread())
.retryWhen(new RetryFunction(3, 3));
}
};
}
}
以上是本次分享,如有不正之處,請多指教!