Android 基於Retrofit2.0的支援多主機地址的網路請求類的封裝
阿新 • • 發佈:2018-12-09
一、首先在Module級別的build.gradle檔案中新增依賴
implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' implementation 'com.squareup.retrofit2:converter-gson:2.2.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0' implementation 'io.reactivex.rxjava2:rxjava:2.0.6' implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
二、程式碼面前,一目瞭然(註釋很清楚)
1、支援多主機地址的網路請求類:HttpApi2.java
package com.yonbor.bettermvp.api; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.yonbor.baselib.base.BaseApplication; import com.yonbor.baselib.utils.NetWorkUtils; 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.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; /** * 支援多主機地址的網路請求類 * yonbor605 */ public class HttpApi2 { //讀超時長,單位:毫秒 public static final int READ_TIME_OUT = 20000; //連線時長,單位:毫秒 public static final int CONNECT_TIME_OUT = 20000; public Retrofit retrofit; public static ApiService apiService; private static SparseArray<HttpApi2> httpApi2SparseArray = new SparseArray<>(HostType.TYPE_COUNT); /*************************快取設定*********************/ /* 1. noCache 不使用快取,全部走網路 2. noStore 不使用快取,也不儲存快取 3. onlyIfCached 只使用快取 4. maxAge 設定最大失效時間,失效則不使用 需要伺服器配合 5. maxStale 設定最大失效時間,失效則不使用 需要伺服器配合 感覺這兩個類似 還沒怎麼弄清楚,清楚的同學歡迎留言 6. minFresh 設定有效時間,依舊如上 7. FORCE_NETWORK 只走網路 8. FORCE_CACHE 只走快取*/ /** * 設快取有效期為兩天 */ private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2; /** * 查詢快取的Cache-Control設定,為if-only-cache時只查詢快取而不會請求伺服器,max-stale可以配合設定快取失效時間 * max-stale 指示客戶機可以接收超出超時期間的響應訊息。如果指定max-stale訊息的值,那麼客戶機可接收超出超時期指定值之內的響應訊息。 */ private static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC; /** * 查詢網路的Cache-Control設定,頭部Cache-Control設為max-age=0 * (假如請求了伺服器並在a時刻返回響應結果,則在max-age規定的秒數內,瀏覽器將不會發送對應的請求到伺服器,資料由快取直接返回)時則不會使用快取而請求伺服器 */ private static final String CACHE_CONTROL_AGE = "max-age=0"; // 構造方法私有 private HttpApi2(int hostType) { //開啟Log HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { Log.e("HttpApi", "OkHttpMessage:" + message); } }); logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); //快取 File cacheFile = new File(BaseApplication.getAppContext().getCacheDir(), "cache"); Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb //增加頭部資訊 Interceptor headerInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request build = chain.request().newBuilder() .addHeader("Content-Type", "application/json") //設定允許請求json資料 .build(); return chain.proceed(build); } }; //建立一個OkHttpClient並設定超時時間 OkHttpClient okHttpClient = new OkHttpClient.Builder() .readTimeout(READ_TIME_OUT, TimeUnit.MILLISECONDS) .connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS) .addInterceptor(mRewriteCacheControlInterceptor) // 自定義的攔截器,用於新增公共引數 .addNetworkInterceptor(mRewriteCacheControlInterceptor) .addInterceptor(headerInterceptor) .addInterceptor(logInterceptor) .cache(cache) .build(); Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").serializeNulls().create(); retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl(ApiConstants.getHost(hostType)) .addConverterFactory(GsonConverterFactory.create(gson)) //請求的結果轉為實體類 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //適配RxJava2.0,RxJava1.x則為RxJavaCallAdapterFactory.create() .build(); apiService = retrofit.create(ApiService.class); } public static ApiService getApiService() { HttpApi2 httpApi2 = httpApi2SparseArray.get(0); if (httpApi2 == null) { httpApi2 = new HttpApi2(0); httpApi2SparseArray.put(0, httpApi2); } return httpApi2.apiService; } public static ApiService getApiService(int hostType) { HttpApi2 httpApi2 = httpApi2SparseArray.get(hostType); if (httpApi2 == null) { httpApi2 = new HttpApi2(hostType); httpApi2SparseArray.put(hostType, httpApi2); } return httpApi2.apiService; } /** * 根據網路狀況獲取快取的策略 */ @NonNull public static String getCacheControl() { return NetWorkUtils.isNetConnected(BaseApplication.getAppContext()) ? CACHE_CONTROL_AGE : CACHE_CONTROL_CACHE; } /** * 雲端響應頭攔截器,用來配置快取策略 * Dangerous interceptor that rewrites the server's cache-control header. */ private final Interceptor mRewriteCacheControlInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); String cacheControl = request.cacheControl().toString(); if (!NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) { request = request.newBuilder() .cacheControl(TextUtils.isEmpty(cacheControl) ? CacheControl.FORCE_NETWORK : CacheControl.FORCE_CACHE) .build(); } Response originalResponse = chain.proceed(request); if (NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) { //有網的時候讀介面上的@Headers裡的配置,你可以在這裡進行統一的設定 return originalResponse.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma") .build(); } else { return originalResponse.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_STALE_SEC) .removeHeader("Pragma") .build(); } } }; }
2、主地址(baseUrl)型別管理類:HostType.java
public class HostType {
/**
* 多少種Host型別
*/
public static final int TYPE_COUNT = 2;
/**
* 首頁型別host
*/
public static final int HOME_NEW_LIST = 1;
/**
* 圖片上傳型別host
*/
public static final int PICTURE_NEW_LIST = 2;
}
3、獲取對應的主機地址的類:ApiConstants.java
public class ApiConstants {
public static final String BASEURL = "http://www.baidu.com/";
/**
* 獲取對應的host
*
* @param hostType host型別
* @return host
*/
public static String getHost(int hostType) {
String host;
switch (hostType) {
case HostType.HOME_NEW_LIST:
host = "http://v.juhe.cn/toutiao/";
break;
case HostType.PICTURE_NEW_LIST:
host = "";
break;
default:
host = "";
break;
}
return host;
}
}
三、如何使用
1、介面類ApiService.java中定義介面
package com.yonbor.bettermvp.api;
import com.yonbor.bettermvp.model.Result;
import com.yonbor.bettermvp.model.ResultModel;
import com.yonbor.bettermvp.model.home.news.NewsListModel;
import java.util.List;
import io.reactivex.Flowable;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface ApiService {
// 聚合新聞頭條介面
@GET("index")
Flowable<ResultModel<Result<List<NewsListModel>>>> getNews(@Query("type") String type, @Query("key") String key);
}
2、聚合資料的新聞頭條介面的呼叫
package com.yonbor.bettermvp.ui.app.home.news;
import android.widget.Toast;
import com.yonbor.baselib.base.BasePresenter;
import com.yonbor.bettermvp.api.HostType;
import com.yonbor.bettermvp.api.HttpApi2;
import com.yonbor.bettermvp.model.Result;
import com.yonbor.bettermvp.model.ResultModel;
import com.yonbor.bettermvp.model.home.news.NewsListModel;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import java.util.List;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* @Description:
* @Author: YinYongbo
* @Time: 2018/8/13 15:22
*/
public class NewsListPresenter extends BasePresenter<NewsListView> {
public void getNewsListData() {
Flowable<ResultModel<Result<List<NewsListModel>>>> flowable = HttpApi2.getApiService(HostType.HOME_NEW_LIST).getNews("top", "9d5c5d5de8c5ff12244879da48f5bfb3");
flowable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ResultModel<Result<List<NewsListModel>>>>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(ResultModel<Result<List<NewsListModel>>> resultResultModel) {
if (resultResultModel.result.data != null) {
List<NewsListModel> list = resultResultModel.result.data;
// String stat = resultResultModel.result.stat;
if (list.size() > 0) {
mView.returnNewsListData(list);
}
} else {
Toast.makeText(mContext, "暫無資料", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
});
}
}