前言
android時下最流行的網(wǎng)絡(luò)框架莫過于 retrofit + rexjava +ok3
本文記錄下我的網(wǎng)絡(luò)架構(gòu)轉(zhuǎn)型記錄渊跋。我項目里面采用的是OK3作網(wǎng)絡(luò)連接層,但是資源的下載我是用的rexjava+OK3單獨寫的一套下載util芋齿,想法就是單獨調(diào)用解耦分離。我采用的就是 retrofit2 + rexjava2 +ok3這樣的一個組合方式。Retrofit實質(zhì)上就是對okHttp的封裝,使用面向接口的方式進(jìn)行網(wǎng)絡(luò)請求欧募,利用動態(tài)生成的代理類封裝了網(wǎng)絡(luò)接口請求的底層,其將請求返回javaBean,對網(wǎng)絡(luò)認(rèn)證 REST API進(jìn)行了很好對支持仆抵。
- 關(guān)于Retrofit 大家可以看下官網(wǎng)的介紹跟继,A type-safe HTTP client for Android and Java。是一個Android和Java安全的httpclient镣丑。
- Retrofit2比Retrofit1在效率的提升是很高效的主要在硬性依賴和抽象舔糖。在Retrofit2中提供okhttp以及okio依賴,OkHttp的類型基本上已經(jīng)以更好更簡潔的 API 替代 Retrofit 1.0 的一些接口。好了暫時介紹這些莺匠,大家可以去看Jake Wharton的retrofit2的介紹以及工作原理金吗。
REST
REST(REpresentational State Transfer)指的是一組架構(gòu)約束條件和原則。滿足這些約束條件和原則的應(yīng)用程序或設(shè)計就是RESTful:
(1)資源(Resources)每一個URI代表一種資源趣竣;
(2)表現(xiàn)層(Representation)客戶端和服務(wù)器之間辽聊,傳遞這種資源的某種表現(xiàn)層;
(3)狀態(tài)轉(zhuǎn)化(State Transfer)客戶端通過四個HTTP動詞期贫,對服務(wù)器端資源進(jìn)行操作跟匆,實現(xiàn)"表現(xiàn)層狀態(tài)轉(zhuǎn)化"。
Retrofit2+Rexjava+Okhttp
在Android gradle中添加retrofithe rexjava okhttp添加依賴通砍。
`
implementation "io.reactivex.rxjava2:rxjava:2.1.1"http://RxJava2.0所需依賴
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'//Rxandroid2.0線程調(diào)度依賴
implementation 'com.squareup.retrofit2:retrofit:2.3.0'//Retrofit2.0所需依賴
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'//結(jié)果轉(zhuǎn)為實體類所需依賴
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'//OKHttp優(yōu)化策略依賴
`
OkHttpClientHelper
首先我們設(shè)計出okhttpclient對象為創(chuàng)建Retrofit提供關(guān)聯(lián)對象OkHttpClientHelper,還有緩存對象CacheHelper玛臂,這里只是貼出相關(guān)的代碼吧。
private OkHttpClientHelper() {
cache = CacheHelper.getInstance().getCache();
}
//單例模式
public static OkHttpClientHelper getInstance() {
if (clientHelper == null) {
synchronized (OkHttpClientHelper.class) {
if (clientHelper == null) {
clientHelper = new OkHttpClientHelper();
}
}
}
return clientHelper;
}
//創(chuàng)建OKHttpClicent對象 配置header頭信息等
public OkHttpClient getOkHttpClient() {
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
if (mClient == null) {
mClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)
.cache(cache) //設(shè)置緩存
.addInterceptor(loggingInterceptor) //配置攔截器log信息
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request()//配置添加header信息
.newBuilder()
.addHeader("source-terminal", "Android") //操作系統(tǒng)名稱(ios,android)//設(shè)備型號
.addHeader("device-model", Build.MODEL) //設(shè)備型號
.addHeader("os-version", Build.VERSION.RELEASE) //操作系統(tǒng)版本號
//添加cookie 這里需要全局觀察下用戶信息--比如cookie可以是uid也可以是usertoken等
.addHeader("Cookie", "add cookies here") //這里可以添加cookie 也可以在設(shè)計的webview中設(shè)置cookie的存儲
.build();
if (API.mode == API.Mode.debug || API.mode == API.Mode.prerelease) {
Logger.e("header=>source-terminal", "Android--" + request.url());
Logger.e("header=>device-model", Build.MODEL);
Logger.e("header=>os-version", Build.VERSION.RELEASE);
Logger.e("header=>Cookie", "");
}
return chain.proceed(request);
}
})
.build();
}
return mClient;
}
相信在看這篇文章的朋友對okhttp應(yīng)該是很了解了封孙,那么就不多過解釋迹冤,創(chuàng)建okclient對象,設(shè)置緩存虎忌,設(shè)置超時讀寫時間泡徙,添加攔截器,添加請求頭信息膜蠢。返回的我們需要的client對象.
RetrofitHelper
上面有了okclient對象堪藐,現(xiàn)在我們可以設(shè)計我們的Retrofit實例,
名字就叫RetrofitHelper挑围。在構(gòu)造方法中我們就獲取到
okhttpclient對象礁竞,在OkHttpClientHelper的構(gòu)造方法中我們又
獲取到 CacheHelper的實例,這樣的好處方便擴展維護(hù)吧杉辙。
`
private RetrofitHelper() {
mClient = OkHttpClientHelper.getInstance().getOkHttpClient();
}
//單例模式 對象唯一
public static RetrofitHelper getInstance() {
if (helper == null) {
synchronized (RetrofitHelper.class) {
if (helper == null) {
helper = new RetrofitHelper();
}
}
}
return helper;
}
`
現(xiàn)在我們需要創(chuàng)建Retrofit對象模捂,Retrofit2和1是有一些區(qū)別的。
具體的區(qū)別大家可以去看下square公司開發(fā)者作者Jake Wharton的介紹用 Retrofit 2 簡化 HTTP 請求)
`
//構(gòu)造Retrofit對象 設(shè)置基礎(chǔ)域名
public Retrofit getRetrofit() {
if (mRetrofit == null) {
mRetrofit = new Retrofit.Builder()
.baseUrl(API.DOMAIN) //域名訪問地址 這里只是為了方便demo單獨寫一個,最好的方式是在builderconfig里面配置狂男,只要修改一下Build Varilant 就可以切換生產(chǎn)環(huán)境
.addConverterFactory(ResponseConverterFactory.create()) // 轉(zhuǎn)換器 添加gson支持 在和后臺配合開發(fā)的過程中 設(shè)計返回數(shù)據(jù)模型解決解析異常
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //添加RxJava支持
.client(mClient) //關(guān)聯(lián)ok3 設(shè)置client
.build();
}
return mRetrofit;
}
我們調(diào)用的方式就比較簡單了综看,直接設(shè)置service
//獲取服務(wù)service對象 對應(yīng)每一個接口都是一個微服務(wù)
public static <T> T getService(Class<T> classz) {
return RetrofitHelper.getInstance()
.getRetrofit()
.create(classz);
}
`
在調(diào)用返回的地方設(shè)置T泛型方便我們使用;添加Rxjava支持,在使用RxJava過程中會發(fā)現(xiàn)RxJava2和RxJava1在語法上有一些區(qū)別,推薦閱讀學(xué)習(xí)這個Rexjavagithub;在添加Converter的時候(Convert objects to and from their representation in HTTP.)可以添加多種序列化Factory岖食,但是GsonConverterFactory必須放在最后,否則會拋出異常寓搬,我們配合后臺在開發(fā)的過程中通常都會設(shè)計好返回的數(shù)據(jù)規(guī)范格式。所以這里我們自己做一下數(shù)據(jù)的解析處理和加解密的操作县耽。這里就不多介紹了句喷,在demo中的我寫了三個類型,GSON FastJson 加解密JSON類型兔毙。有需要的朋友可以針對性看一下就可以了唾琼。
ApiService
api服務(wù)注解方式 這個是官方給開發(fā)者學(xué)習(xí)使用的類型
方法注解包含 :
@GET、@POST澎剥、@PUT锡溯、@DELETE、
@PATH哑姚、@HEAD祭饭、@OPTIONS、@HTTP叙量。
標(biāo)記注解包含:
@FormUrlEncoded倡蝙、@Multipart、@Streaming绞佩。
參數(shù)注解包含:
@Query,@QueryMap寺鸥、@Body、@Field品山,@FieldMap胆建、@Part,@PartMap肘交。
其他注解包含:
@Path笆载、@Header,@Headers、@Url
這里舉一個我們的例子
@GET("/v1/resource/search/{searchname}?suggest=true")
Observable<SearchDataList.DataBean> getSearchVideo(@Path("searchname") String searchname, @Query("rank") String rank, @Query("size") String size);
NetWorkUtil
網(wǎng)絡(luò)調(diào)用方法util,demo里我只寫了一中方法涯呻,最近工作比較忙凉驻,擴充類型等有時間再去弄了。rexjava2訂閱綁定設(shè)置io
‘
public class NetWorkUtil {
//對應(yīng)HTTP的狀態(tài)碼
private static final int UNAUTHORIZED = 401;
private static final int FORBIDDEN = 403;
private static final int NOT_FOUND = 404;
private static final int REQUEST_TIMEOUT = 408;
private static final int INTERNAL_SERVER_ERROR = 500;
private static final int BAD_GATEWAY = 502;
private static final int SERVICE_UNAVAILABLE = 503;
private static final int GATEWAY_TIMEOUT = 504;
//Post方式
public static <T> void requestPost(Observable observable, final OnResultListener resultListener) {
setSubscriber(observable, new Observer<T>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(T t) {
if (resultListener != null) {//找一些接口試一下就好了
resultListener.onSuccess(t);
}
// if (t instanceof BaseResponseBean) {
// //后臺可配置code碼 根據(jù)不同的code可以做相應(yīng)的操作 比如后臺強制拋出錯誤等等 這里我注釋掉魄懂,給大家個樣板而已
// BaseResponseBean success = (BaseResponseBean) t;
// if (success.code == 0) {
// if (resultListener != null) {
// resultListener.onSuccess(success.data);
// }
// } else {
// if (resultListener != null) {
// resultListener.onError(success.errormessage);
// }
// }
// } else {
// if (resultListener != null) {
// resultListener.onError("數(shù)據(jù)異常了");
// }
// }
}
@Override
public void onError(Throwable error) {
if (error != null && resultListener != null) {
resultListener.onError(error.getMessage());
} else if (resultListener != null) {
resultListener.onError("兄弟 網(wǎng)絡(luò)不給力啊");
return;
}
String e = error.getMessage();
if (error instanceof HttpException) {//HTTP錯誤
HttpException httpException = (HttpException) error;
switch (httpException.code()) {
case UNAUTHORIZED:
case FORBIDDEN:
case NOT_FOUND:
case REQUEST_TIMEOUT:
case GATEWAY_TIMEOUT:
case INTERNAL_SERVER_ERROR:
case BAD_GATEWAY:
case SERVICE_UNAVAILABLE:
default:
//Toast.makeText(App.getInstance(), "網(wǎng)絡(luò)異常", Toast.LENGTH_SHORT).show();
break;
}
} else if (error instanceof SocketTimeoutException) {
} else if (error instanceof JsonParseException || error instanceof JSONException || error instanceof ParseException) {
} else if (error instanceof ResultException) {//服務(wù)器返回的錯誤
} else if (error instanceof ConnectException) {
} else {//未知錯誤
}
resultListener.onError("兄弟 網(wǎng)絡(luò)不給力啊");
}
@Override
public void onComplete() {
// Logger.d("request", "讀取完成");
}
});
}
//Get方式
public static void requestGet(Observable observable, final OnResultListener resultListener) {
requestPost(observable, resultListener);
}
//訂閱事件
public static <T> void setSubscriber(Observable<T> observable, Observer<T> subscriber) {
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
//網(wǎng)絡(luò)訪問回調(diào)接口
public interface OnResultListener<T> {
void onSuccess(T t);
void onError(String msg);
}
}
’
可以看到我們在apiservice里面定義了一個服務(wù)(接口方法)返回Observable泛型內(nèi)容是我們想要的對象沿侈。在上面NetWorkUtil里面調(diào)用方法中,rexjava2的方法就大家自行學(xué)習(xí)了市栗。在這里面有共用的網(wǎng)絡(luò)錯誤類型。已經(jīng)在retrofit幫助類里面設(shè)置ConverterFactory里面定義解析失敗的類型。到此就全部描述完這個工作流程填帽。下面舉一個具體調(diào)用的示例蛛淋。(為什么沒有封裝成mvp模式呢,我覺得我們不是為了設(shè)計模式而設(shè)計模式篡腌,在部分需求以及開發(fā)中我覺得采用適當(dāng)?shù)脑O(shè)計模式有助于項目開發(fā)和維護(hù)提升性能褐荷,但是在單獨的網(wǎng)絡(luò)層中,我覺得自己做自己的事情更加解耦性)
`
public void getData() {
//簡單好用嘹悼,看log就明白了
Observable<SearchDataList.DataBean> searchVideo = RetrofitHelper.getService(ApiService.class).getSearchVideo("秋冬編發(fā)大全", "0", "20");
//這個直接返回來數(shù)據(jù)對象
NetWorkUtil.requestGet(searchVideo, new NetWorkUtil.OnResultListener() {
@Override
public void onSuccess(Object o) {
SearchDataList.DataBean bean = (SearchDataList.DataBean) o;
setdata(bean);
}
@Override
public void onError(String msg) {
}
});
}
`
到這里就差不多介紹完了下面給出git鏈接 下載看這里 覺得還行記得star 感謝各位叛甫,語言組織不好還請諒解。杨伙。其监。各位看官小手抖一抖雙擊666