package com.troy.xifan.http; import com.facebook.stetho.okhttp3.StethoInterceptor; import com.orhanobut.logger.Logger; import com.troy.xifan.App; import com.troy.xifan.api.ApiFactory; import com.troy.xifan.config.Constants; import com.troy.xifan.http.callback.HttpRequestCallback; import com.troy.xifan.http.converter.ResponseConverterFactory; import com.troy.xifan.http.exception.ApiException; import com.troy.xifan.http.exception.ErrorCode; import com.troy.xifan.http.exception.ExceptionHandle; import com.troy.xifan.http.request.BaseRequestParams; import com.troy.xifan.http.response.HttpResponseData; import com.troy.xifan.util.NetUtils; import com.troy.xifan.util.XAuthUtils; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; import okhttp3.Cache; import okhttp3.CacheControl; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import rx.Observable; import rx.Subscriber; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action0; import rx.functions.Func1; import rx.schedulers.Schedulers; /** * Created by chenlongfei on 2016/11/19. */ public class HttpRequestFactory { //超时60s private static final long TIMEOUT = 60; private static final int CACHE_SIZE = 10 * 1024 * 1024; private static HttpRequestFactory mInstance; private ApiFactory mServiceFactory; public HttpRequestFactory() { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.HEADERS); OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(TIMEOUT, TimeUnit.SECONDS) .readTimeout(TIMEOUT, TimeUnit.SECONDS) .writeTimeout(TIMEOUT, TimeUnit.SECONDS) .cache(getCache()) .addInterceptor(logging) .addNetworkInterceptor(mTokenInterceptor) //应用拦截器,用于离线缓存 .addInterceptor(mCacheInterceptor) //网络拦截器,用于在线缓存 .addNetworkInterceptor(mCacheInterceptor) .addNetworkInterceptor(new StethoInterceptor()) .build(); Retrofit retrofit = new Retrofit.Builder().baseUrl(Constants.FanFou.FANFOU_API_URL) .addConverterFactory(ResponseConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(okHttpClient) .build(); mServiceFactory = retrofit.create(ApiFactory.class); } public static HttpRequestFactory getInstance() { if (mInstance == null) { synchronized (HttpRequestFactory.class) { if (mInstance == null) { mInstance = new HttpRequestFactory(); } } } return mInstance; } private Cache getCache() { File file = new File(App.getInstance().getCacheDir(), "response"); return new Cache(file, CACHE_SIZE); } public void getAccessToken(String username, String password, HttpRequestCallback callback) { subscribe(mServiceFactory.getAccessToken(Constants.FanFou.ACCESS_TOKEN_URL), callback); } public void getHomeTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getHomeTimeline(requestParams.convertToQueryMap()), callback); } public void getUserHomeTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getUserTimeline(requestParams.convertToQueryMap()), callback); } public void getPublicTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getPublicTimeline(requestParams.convertToQueryMap()), callback); } public void destroyStatus(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.destroyStatus(requestParams.convertToBodyMap()), callback); } public void updateStatus(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.updateStatus(requestParams.convertToBodyMap()), callback); } public void uploadPhoto(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.uploadPhoto(requestParams.convertToBodyMap()), callback); } public void getUserPhotos(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getUserPhotos(requestParams.convertToQueryMap()), callback); } public void getMentions(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getMentions(requestParams.convertToQueryMap()), callback); } public void getConversationList(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getConversationList(requestParams.convertToQueryMap()), callback); } public void getConversation(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getConversation(requestParams.convertToQueryMap()), callback); } public void sendDirectMessage(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.sendDirectMessage(requestParams.convertToBodyMap()), callback); } public void createFavorite(String id, HttpRequestCallback callback) { subscribe(mServiceFactory.createFavorite(id), callback); } public void destroyFavorite(String id, HttpRequestCallback callback) { subscribe(mServiceFactory.destroyFavorite(id), callback); } public void getUserFavorites(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getUserFavorites(requestParams.convertToQueryMap()), callback); } public void getFriends(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getFriends(requestParams.convertToQueryMap()), callback); } public void getFollowers(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getFollowers(requestParams.convertToQueryMap()), callback); } public void getUserInfo(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.getUserInfo(requestParams.convertToQueryMap()), callback); } public void getTrends(HttpRequestCallback callback) { subscribe(mServiceFactory.getTrends(), callback); } public void searchPublicTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.searchPublicTimeline(requestParams.convertToQueryMap()), callback); } public void searchUser(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.searchUser(requestParams.convertToQueryMap()), callback); } public void searchUserTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.searchUserTimeline(requestParams.convertToQueryMap()), callback); } public void createFriendship(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.createFriendship(requestParams.convertToBodyMap()), callback); } public void destroyFriendship(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.destoryFriendship(requestParams.convertToBodyMap()), callback); } public void isExistFriendship(BaseRequestParams requestParams, HttpRequestCallback callback) { subscribe(mServiceFactory.isExistFriendship(requestParams.convertToQueryMap()), callback); } public void getNotification(HttpRequestCallback callback) { subscribe(mServiceFactory.getNotification(), callback); } private <T> void subscribe(Observable<HttpResponseData<T>> observable, HttpRequestCallback callback) { observable.map(new HttpResponseFunc<T>()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe(new DoOnSubscribe(callback)) .subscribeOn(AndroidSchedulers.mainThread()) .onErrorResumeNext(new HttpErrorResult<T>()) .retryWhen(new RetryWithError()) .subscribe(new HttpSubscriber<T>(callback)); } //map变换 private class HttpResponseFunc<T> implements Func1<HttpResponseData<T>, T> { @Override public T call(HttpResponseData<T> httpResponseData) { return httpResponseData.getData(); } } //在事件发送前执行,用来在界面上显示loading private class DoOnSubscribe implements Action0 { private HttpRequestCallback mCallback; public DoOnSubscribe(HttpRequestCallback callback) { mCallback = callback; } @Override public void call() { mCallback.onStart(); } } private class HttpSubscriber<T> extends Subscriber<T> { private HttpRequestCallback mCallback; public HttpSubscriber(HttpRequestCallback callback) { mCallback = callback; } @Override public void onStart() { } @Override public void onCompleted() { } @Override public void onError(Throwable e) { if (e instanceof ApiException) { mCallback.onFail((ApiException) e); } } @Override public void onNext(T t) { mCallback.onSuccess(t); } } //异常预处理 private class HttpErrorResult<T> implements Func1<Throwable, Observable<T>> { @Override public Observable<T> call(Throwable throwable) { return Observable.error(ExceptionHandle.handleException(throwable)); } } //重试 private class RetryWithError implements Func1<Observable<? extends Throwable>, Observable<?>> { //最大重试次数 private int maxRetry = 3; //间隔时间ms private static final int INTERVAL = 1000; @Override public Observable<?> call(Observable<? extends Throwable> observable) { return observable.flatMap(new Func1<Throwable, Observable<?>>() { @Override public Observable<?> call(Throwable throwable) { //网络超时重试 if (throwable instanceof ApiException) { ApiException apiException = (ApiException) throwable; if (apiException.getErrorCode().equals(ErrorCode.ERROR_NET_TIMEOUT) && maxRetry-- > 0) { return Observable.timer(INTERVAL, TimeUnit.MILLISECONDS); } } return Observable.error(throwable); } }); } } //TokenInterceptor add authorization private Interceptor mTokenInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); Request.Builder builder = originalRequest.newBuilder(); Request tokenRequest = builder.header(Constants.HeaderName.AUTHORIZATION, XAuthUtils.getAuthorization(originalRequest)).build(); return chain.proceed(tokenRequest); } }; //http 数据缓存 private Interceptor mCacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //无网络时走okhttp 内部缓存机制 if (!NetUtils.isNetworkConnected(App.getInstance())) { //在请求首部中声明读取缓存内容 request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build(); } Response originalResponse = chain.proceed(request); Logger.d("success:" + originalResponse.isSuccessful()); //有网络时不读缓存 if (NetUtils.isNetworkConnected(App.getInstance())) { return originalResponse.newBuilder() .header("Cache-Control", request.cacheControl().toString()) .removeHeader("Pragma") .build(); } else { int maxAge = 60 * 60 * 24; return originalResponse.newBuilder() .header("Cache-Control", "public, only-if-cached, max-age=" + maxAge) .removeHeader("Pragma") .build(); } } }; }