
前言
android時下最流行的網(wǎng)絡(luò)框架莫過于 retrofit + rexjava +ok3
本文記錄下我的網(wǎng)絡(luò)架構(gòu)轉(zhuǎn)型記錄。我項(xiàng)目里面采用的是OK3作網(wǎng)絡(luò)連接層,但是資源的下載我是用的rexjava+OK3單獨(dú)寫的一套下載util,想法就是單獨(dú)調(diào)用解耦分離。我采用的就是 retrofit2 + rexjava2 +ok3這樣的一個組合方式。Retrofit實(shí)質(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)行操作,實(shí)現(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)為實(shí)體類所需依賴
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實(shí)例,
名字就叫RetrofitHelper。在構(gòu)造方法中我們就獲取到
okhttpclient對象,在OkHttpClientHelper的構(gòu)造方法中我們又
獲取到 CacheHelper的實(shí)例,這樣的好處方便擴(kuò)展維護(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單獨(dú)寫一個,最好的方式是在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里我只寫了一中方法,最近工作比較忙,擴(kuò)充類型等有時間再去弄了。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)的操作 比如后臺強(qiá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è)計模式有助于項(xiàng)目開發(fā)和維護(hù)提升性能,但是在單獨(dú)的網(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
