Android 網絡框架(二)之Retrofit+RxJava網絡框架封裝

       這篇文章主要闡述在實際開發中如何封裝我們自己的網絡通信框架,網絡框架需提供請求日誌、失敗重試、異步請求等功能,如果你想了解這些,那看這篇文章就對了。如果你對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));
            }
        };
    }
}

 

以上是本次分享,如有不正之處,請多指教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章