天天看點

Retrofit2+OkHttp3+RxJave 三劍客解決網絡問題

public class RetrofitManager {





    /**
     * 需要的引用
     *   retrofit2 + okhttp3 引用
     *    compile 'com.android.support.constraint:constraint-layout:1.0.2'
     *    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
     *    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
     *    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
     *    compile 'com.squareup.retrofit2:converter-scalars:2.0.0-beta4'
     *    compile 'com.squareup.okhttp3:okhttp:3.2.0'
     *    compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
     *    compile 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
     *
     *   rxjava引用
     *    compile 'io.reactivex:rxandroid:1.1.0'
     *    compile 'io.reactivex:rxjava:1.1.0'
     *
     * 拼url 的資料            @see{     http://blog.csdn.net/linzhenxiang123/article/details/52593971  }
     *
     * cookie持久化解決方案    @see{     https://github.com/franmontiel/PersistentCookieJar      }
     *
     */

    private static final long TIMEOUT = 1000 * 30;
    private static final String BASE_URL="http://gank.io/api/";

    private static RetrofitManager retrofitManager;
    protected ApiService apiService;


    private RetrofitManager(Context context) {
        OkHttpClient client = initOkHttpClient(context);
        Retrofit retrofit = initRetrofit(client);
        apiService = retrofit.create(ApiService.class);
    }

    /**
     * 初始化okhttp
     *
     * @param context
     * @return
     */
    private OkHttpClient initOkHttpClient(Context context) {
        //建立一個檔案用來緩存網絡請求
        File cacheDirectory = new File(context.getCacheDir().getAbsolutePath(), "HttpCache");
        ClearableCookieJar cookieJar =
                new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
        //執行個體化一個OkHttpClient.Builder
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(TIMEOUT, TimeUnit.SECONDS)//設定連接配接逾時
                .readTimeout(TIMEOUT, TimeUnit.SECONDS)//設定從主機讀資訊逾時
                .writeTimeout(TIMEOUT, TimeUnit.SECONDS)//設定寫資訊逾時
                .retryOnConnectionFailure(true)///如果連接配接失敗,嘗試重連
                .cache(new Cache(cacheDirectory, 10 * 1024 * 1024))//設定緩存檔案
                .addInterceptor(initInterceptor())//設定okhttp攔截器,這樣做的好處是可以為你的每一個retrofit2的網絡請求都增加相同的head頭資訊,而不用每一個請求都寫頭資訊
                .addInterceptor(initLogInterceptor())//列印日志
                .cookieJar(cookieJar)
                .build();
        return client;
    }

    /**
     * 初始化http攔截器
     *
     * @return
     */
    private Interceptor initInterceptor() {
        BasicParamsInterceptor builder =new BasicParamsInterceptor.Builder()
                .addHeaderParam("Content-Type", "application/json; charset=UTF-8")
                .addHeaderParam("Connection", "keep-alive")
                .addHeaderParam("Accept", "*/*")
                .addHeaderParam("Cache-Control", String.format("public, max-age=%d", 60))
                .build();
        return builder;
    }

    private Interceptor initLogInterceptor(){
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Log.i("info", "請求參數:" + message);
            }
        });
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        return  interceptor;
    }


    /**
     * 初始化  Retrofit
     * @param client
     * @return
     */
    private Retrofit initRetrofit(OkHttpClient client) {
        Retrofit builder = new Retrofit.Builder()
                .client(client)//設定 HTTP Client  用于請求的連接配接
                .addConverterFactory(ScalarsConverterFactory.create())//如果網絡通路傳回的字元串,而不是json資料格式,要使用下面的轉換器
                .addConverterFactory(GsonConverterFactory.create())//如果網絡通路傳回的是json字元串,使用gson轉換器
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//此處順序不能和上面對調,否則不能同時相容普通字元串和Json格式字元串  為了支援rxjava,需要添加下面這個把 Retrofit 轉成RxJava可用的适配類
                .baseUrl(BASE_URL)//請求的父目錄
                .build();
        return builder;
    }


    public static RetrofitManager getInstance(Context context) {
        if (retrofitManager == null) {
            synchronized (RetrofitManager.class) {
                if (retrofitManager == null)
                    retrofitManager = new RetrofitManager(context);
            }
        }
        return retrofitManager;
    }

    public ApiService getApiService(){
        return apiService;
    }

}      
public abstract class ApiCallBack<T> extends Subscriber<T> {

    protected abstract void onSuccess(T t);

    protected  abstract void onFailure();

    protected  abstract void onFinish();


    @Override
    public void onCompleted() {
        onFinish();
    }

    @Override
    public void onError(Throwable e) {
        if(e instanceof HttpException){
            HttpException exception = (HttpException)e;
            int code = exception.response().code();
            Log.i("info","code:"+code);
        }else if (e instanceof JsonParseException
                || e instanceof JSONException) {
            Log.i("info","code:解析錯誤");
        } else if (e instanceof ConnectException) {
            Log.i("info","code:連接配接失敗");
        } else if (e instanceof javax.net.ssl.SSLHandshakeException) {
            Log.i("info","code:證書驗證失敗");
        } else {
            Log.i("info","code:未知錯誤");
        }
        onFailure();
    }

    @Override
    public void onNext(T t) {
        onSuccess(t);
    }
}      
public class BasicParamsInterceptor implements Interceptor {

    Map<String, String> queryParamsMap = new HashMap<>();
    Map<String, String> paramsMap = new HashMap<>();
    Map<String, String> headerParamsMap = new HashMap<>();
    List<String> headerLinesList = new ArrayList<>();

    private BasicParamsInterceptor() {

    }

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();
        Request.Builder requestBuilder = request.newBuilder();

        // process header params inject
        Headers.Builder headerBuilder = request.headers().newBuilder();
        if (headerParamsMap.size() > 0) {
            Iterator iterator = headerParamsMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                headerBuilder.add((String) entry.getKey(), (String) entry.getValue());
            }
        }

        if (headerLinesList.size() > 0) {
            for (String line: headerLinesList) {
                headerBuilder.add(line);
            }
        }

        requestBuilder.headers(headerBuilder.build());
        // process header params end




        // process queryParams inject whatever it's GET or POST
        if (queryParamsMap.size() > 0) {
            injectParamsIntoUrl(request, requestBuilder, queryParamsMap);
        }
        // process header params end




        // process post body inject
        if (request.method().equals("POST") && request.body().contentType().subtype().equals("x-www-form-urlencoded")) {
            FormBody.Builder formBodyBuilder = new FormBody.Builder();
            if (paramsMap.size() > 0) {
                Iterator iterator = paramsMap.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry entry = (Map.Entry) iterator.next();
                    formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());
                }
            }
            RequestBody formBody = formBodyBuilder.build();
            String postBodyString = bodyToString(request.body());
            postBodyString += ((postBodyString.length() > 0) ? "&" : "") +  bodyToString(formBody);
            requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString));
        } else {    // can't inject into body, then inject into url
            injectParamsIntoUrl(request, requestBuilder, paramsMap);
        }

        request = requestBuilder.build();
        return chain.proceed(request);
    }

    // func to inject params into url
    private void injectParamsIntoUrl(Request request, Request.Builder requestBuilder, Map<String, String> paramsMap) {
        HttpUrl.Builder httpUrlBuilder = request.url().newBuilder();
        if (paramsMap.size() > 0) {
            Iterator iterator = paramsMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                httpUrlBuilder.addQueryParameter((String) entry.getKey(), (String) entry.getValue());
            }
        }

        requestBuilder.url(httpUrlBuilder.build());
    }

    private static String bodyToString(final RequestBody request){
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            if(copy != null)
                copy.writeTo(buffer);
            else
                return "";
            return buffer.readUtf8();
        }
        catch (final IOException e) {
            return "did not work";
        }
    }

    public static class Builder {

        BasicParamsInterceptor interceptor;

        public Builder() {
            interceptor = new BasicParamsInterceptor();
        }

        public Builder addParam(String key, String value) {
            interceptor.paramsMap.put(key, value);
            return this;
        }

        public Builder addParamsMap(Map<String, String> paramsMap) {
            interceptor.paramsMap.putAll(paramsMap);
            return this;
        }

        public Builder addHeaderParam(String key, String value) {
            interceptor.headerParamsMap.put(key, value);
            return this;
        }

        public Builder addHeaderParamsMap(Map<String, String> headerParamsMap) {
            interceptor.headerParamsMap.putAll(headerParamsMap);
            return this;
        }

        public Builder addHeaderLine(String headerLine) {
            int index = headerLine.indexOf(":");
            if (index == -1) {
                throw new IllegalArgumentException("Unexpected header: " + headerLine);
            }
            interceptor.headerLinesList.add(headerLine);
            return this;
        }

        public Builder addHeaderLinesList(List<String> headerLinesList) {
            for (String headerLine: headerLinesList) {
                int index = headerLine.indexOf(":");
                if (index == -1) {
                    throw new IllegalArgumentException("Unexpected header: " + headerLine);
                }
                interceptor.headerLinesList.add(headerLine);
            }
            return this;
        }

        public Builder addQueryParam(String key, String value) {
            interceptor.queryParamsMap.put(key, value);
            return this;
        }

        public Builder addQueryParamsMap(Map<String, String> queryParamsMap) {
            interceptor.queryParamsMap.putAll(queryParamsMap);
            return this;
        }

        public BasicParamsInterceptor build() {
            return interceptor;
        }

    }
}      
public interface ApiService {


//    @POST("site/search")
//    Observable<SearchResult> search(@Body SearchRequestBody searchRequestBody);
    /**
     * 擷取App啟動頁資訊
     * @return
     */
    @GET("json/page/app-data/info.json?v=3.0.1&os=1&ver=4")
    Observable<AppStart> getAppStartInfo();

    // 随機資料
    @GET("random/data/{type}/{count}")
    Observable<GankModel> loadRandomData(@Path("type")String type , @Path("count") int count);
}      
public class BaseActivity extends AppCompatActivity {
    private CompositeSubscription compositeSubscription;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        compositeSubscription = new CompositeSubscription();
    }

    @Override
    protected void onDestroy() {
        if (compositeSubscription.hasSubscriptions()) {
            compositeSubscription.unsubscribe();
        }
        super.onDestroy();
    }

    public void doHttpRequest(Observable observable, Subscriber subscriber) {
        compositeSubscription.add(
                observable.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(subscriber));
    }
}      
public class GankModel {


    private boolean error;
    List<Results> results;

    public boolean getError() {
        return error;
    }

    public void setError(boolean error) {
        this.error = error;
    }

    public List<Results> getResults() {
        return results;
    }

    public void setResults(List<Results> results) {
        this.results = results;
    }

    public static class Results {
        private String _id;
        private String createdAt;
        private String desc;
        private String publishedAt;
        private String type;
        private String url;
        private boolean used;
        private String who;

        public String get_id() {
            return _id;
        }

        public void set_id(String _id) {
            this._id = _id;
        }

        public String getCreatedAt() {
            return createdAt;
        }

        public void setCreatedAt(String createdAt) {
            this.createdAt = createdAt;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        public String getPublishedAt() {
            return publishedAt;
        }

        public void setPublishedAt(String publishedAt) {
            this.publishedAt = publishedAt;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public boolean isUsed() {
            return used;
        }

        public void setUsed(boolean used) {
            this.used = used;
        }

        public String getWho() {
            return who;
        }

        public void setWho(String who) {
            this.who = who;
        }

        @Override
        public String toString() {
            return "Results{" +
                    "_id='" + _id + '\'' +
                    ", createdAt='" + createdAt + '\'' +
                    ", desc='" + desc + '\'' +
                    ", publishedAt='" + publishedAt + '\'' +
                    ", type='" + type + '\'' +
                    ", url='" + url + '\'' +
                    ", used=" + used +
                    ", who='" + who + '\'' +
                    '}';
        }
    }
}      

調用方法

doHttpRequest(RetrofitManager.getInstance(this).getApiService().loadRandomData("福利", 20), new ApiCallBack<GankModel>() {
    @Override
    protected void onSuccess(GankModel gankModels) {
            Log.i("info","gankModel--->"+gankModels.getError());
    }

    @Override
    protected void onFailure() {
        Log.i("info","------------------onFailure----------------");
    }

    @Override
    protected void onFinish() {
        Log.i("info","------------------onFinish----------------");
    }

    @Override
    public void onStart() {

    }
});      

資源位址:       http://download.csdn.net/detail/qq_22256027/9902831

繼續閱讀