rxjava+retrofit+okhttp3
重所周知 當(dāng)下最流行的網(wǎng)絡(luò)請(qǐng)求的框架非rxjava+retrofit+okhttp3三合一了 但是在網(wǎng)絡(luò)上總是找不到一個(gè)比較全面的介紹 于是呼我自己研究了一套網(wǎng)絡(luò)請(qǐng)求的發(fā)開框架 目前已經(jīng)寫入我開發(fā)的項(xiàng)目當(dāng)中 目前還在學(xué)習(xí)的小伙伴們可以學(xué)習(xí)一下
(此篇文章主要針對(duì)我的demo 很多細(xì)節(jié)的東西講的不是很到位 但是我會(huì)把我在網(wǎng)上看的比較好的文章貼上去 讓大家詳細(xì)的了解)
簡潔:對(duì)于rxjava的理解 我個(gè)人認(rèn)為就是一個(gè)異步線程一個(gè)基于事件處理的庫 讓人們可以更簡潔的處理一個(gè)事件的邏輯關(guān)系 簡單性 可讀性 重復(fù)性。再往深處的理解大家也可以認(rèn)為他是擴(kuò)展了開發(fā)者模式演變過來的
當(dāng)然我說的可能會(huì)比較粗糙,我給大家介紹一個(gè)對(duì)Rxjava理解比較好的作者 相信你們看了他的講解 會(huì)比我這里更加的明白和理解。點(diǎn)擊-拋物線
簡潔:Retrofit與okhttp共同出自于Square公司,retrofit就是對(duì)okhttp做了一層封裝。把網(wǎng)絡(luò)請(qǐng)求都交給給了Okhttp,我們只需要通過簡單的配置就能使用retrofit來進(jìn)行網(wǎng)絡(luò)請(qǐng)求。
Retrofit與Okhttp不同的是,Retrofit需要定義一個(gè)接口,用來返回我們的Call對(duì)象
public interface RequestServes {
@POST("mobileLogin/submit.html")
Call getReslut(@Query("loginname") String loginname);
}
或
public interface ApiManagerService {
@POST("/biz/bizserver/news/list.do")
Observable getReslut(@QueryMap Map option);
}
我先說一下Result類,這是我自己demo中使用的實(shí)體類接數(shù)據(jù)的,我是結(jié)合了rxjava的Subscriber(觀察者)來封裝的后面的文段我會(huì)在次講解 這里給大家留個(gè)懸念
顯而易見@POST,@GET的是請(qǐng)求方式,參數(shù)注解有@PATH和@Query,@QueryMap等。 @Query @QueryMap 參數(shù)依舊遵循了http協(xié)議 以鍵值對(duì)的形式進(jìn)行請(qǐng)求。
到此接口我們就定義完成了需要來定義Retrofit對(duì)象來進(jìn)行請(qǐng)求了
俺就不再廢話了 直接貼上代碼 讓大家伙看個(gè)明白地
// OkHttp3 的監(jiān)聽
private static class LogInterceptor implements Interceptor {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Log.e(TAG, "okhttp3:" + request.toString());//輸出請(qǐng)求前整個(gè)url
long t1 = System.nanoTime();
okhttp3.Response response = chain.proceed(chain.request());
long t2 = System.nanoTime();
//? ? ? ? ? Log.v(TAG,response.request().url()+response.headers());//輸出一個(gè)請(qǐng)求的網(wǎng)絡(luò)信息
okhttp3.MediaType mediaType = response.body().contentType();
String content = response.body().string();
Log.e(TAG, "response body:" + content);//輸出返回信息
return response.newBuilder()
.body(okhttp3.ResponseBody.create(mediaType, content))
.build();
}
}
這是OkHttp3自帶的監(jiān)聽可以輸出整個(gè)url 還可以打印請(qǐng)求數(shù)據(jù)的時(shí)間 讓開發(fā)者很清楚的了解請(qǐng)求的耗時(shí)操作流程-真心的良心制作
//初始化OkHttp3的初始化
private static OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LogInterceptor())
.cache(new Cache(new File("C://okhttp"), 10 * 1024 * 102))//緩存
.retryOnConnectionFailure(true)
//? ? ? ? ? .connectTimeout(3, TimeUnit.SECONDS)
//? ? ? ? ? .writeTimeout(5, TimeUnit.SECONDS)
//? ? ? ? ? .readTimeout(5, TimeUnit.SECONDS)
.build();
這是化OkHttp3的初始化
4:鏈接,讀,寫的時(shí)間 可以自己設(shè)置 當(dāng)然不寫也無所謂啦
//初始化Retrofit
private static final Retrofit sRetrofit = new Retrofit.Builder()
.baseUrl("http://api.1-blog.com")
.client(client)
.addConverterFactory(JacksonConverterFactory.create())//加入jackjson解析
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 使用RxJava作為回調(diào)適配器
.build();
初始化Retrofit
2:添加okhttp的對(duì)象(前面也說了-retrofit就是對(duì)okhttp做了一層封裝)
3: 重點(diǎn)來 重點(diǎn)來 重點(diǎn)來重要的事情要說三遍
Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
總有一款你需要的解析形式 附贈(zèng)官網(wǎng)retrofit 官網(wǎng)地址:http://square.github.io/retrofit/啟動(dòng)你的翻譯器慢慢看吧!(英語大神除外哈) 大家可以看到 我添加的是jackjson解析 這是我demo中所需要的 后續(xù)一起講解。 在此介紹一片文章點(diǎn)擊一下吧
@OnClick(R.id.btn)
void more() {
Map result = ApiManager.getBasicMap();
result.put("size", "3");
ApiManager.apiManager.getReslut(result)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new MySubscriber() {
@Override
public void onMyNext(String jsonStr) {
LogUtil.defLog(jsonStr);
data.setText(jsonStr);
}
@Override
public void onMyError(String msg) {
}
@Override
public void onMyCompleted() {
}
});
}
朋友 看到這請(qǐng)你告訴我 你是不是一臉的懵b 別著急 前面介紹了半天 現(xiàn)在正主正在一點(diǎn)點(diǎn)的出來了 咱們一步步的走我來給你解釋一下
###### 1 :Map集合ApiManager.getBasicMap() 自己封裝了一下 可以將以后項(xiàng)目中的公共參數(shù)放進(jìn)去
/**
* 設(shè)置公共參數(shù)
*/
public static Map getBasicMap() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
if (map == null) {
map = new HashMap<>();
} else {
map.clear();
}
//打印MAP
Set> entrySet = map.entrySet();
for (Map.Entry entry : entrySet) {
LogUtil.printI(LogUtil.APP_TAG, entry.getKey() + "http://" + entry.getValue() + "");
}
return map;
}
其中objectMapper 即是jackjson的解析設(shè)置
a)objectMapper.enable 一個(gè)簡單的映射過程 確保數(shù)據(jù)能夠全部請(qǐng)求過來
以上兩個(gè)配置我個(gè)人介意還是加上 省的大家走很多的彎路 (我不哭)
2:ApiManager.apiManager.getReslut(result)
在此調(diào)用網(wǎng)絡(luò)請(qǐng)求
public static ApiManagerService apiManager = sRetrofit.create(ApiManagerService.class);
在開始介紹的由Retrofit定義的接口類 各種的封裝啊。。。。 OK
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
設(shè)置流文件處理,設(shè)置執(zhí)行在主線程。
4:.subscribe(new MySubscriber() What is fuck?
你猜對(duì)了 我又給封裝了
public abstract class MySubscriber extends Subscriber {
String TAG = MySubscriber.class.getName();
@Override
public void onStart() {
onMyStart();
}
@Override
public void onCompleted() {
onMyCompleted();
}
@Override
public void onError(Throwable errorMsg) {
String stringErr = errorMsg.getLocalizedMessage();
//TODO 需要完善異常的判斷
if (stringErr.contains("UnknownHostException")) {
onMyError("無法連接服務(wù)器,請(qǐng)檢查網(wǎng)絡(luò)是否正常");
} else {
onMyError(stringErr);
}
}
@Override
public void onNext(T t) {
if (Result.class.isInstance(t)) {
Result result = (Result) t;
if (!result.getStatus().equals("success")) {
onMyError(result.getInfo());
} else {
if (null == result.getData() && "".equals(result.getData())) {
onMyError("返回?cái)?shù)據(jù)為空");
return;
} else {
try {
String jsonStr = ApiManager.objectMapper.writeValueAsString(result.getData());
onMyNext(jsonStr);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
} else {
//如果沒返回?cái)?shù)據(jù)沒指向Result,打印數(shù)據(jù)。后期有返回特殊數(shù)據(jù)格式的時(shí)候可以單獨(dú)解析jsonStr
try {
String jsonStr = ApiManager.objectMapper.writeValueAsString(t);
//? ? ? ? ? ? ? ? onMyNext(jsonStr);
LogUtil.printE(TAG, "原始數(shù)據(jù)" + jsonStr);
} catch (JsonProcessingException e) {
}
}
}
public abstract void onMyStart();
public abstract void onMyNext(String jsonStr);
public abstract void onMyError(String msg);
public abstract void onMyCompleted();
雖然這里類在代碼里有 但是我還是選擇了全部貼出來 講解開始:
1:創(chuàng)建一個(gè)抽象類MySubscriber 繼承Subscriber 人有會(huì)問 為啥里面帶范型 T 呢
范型的定義:泛型,即“參數(shù)化類型”。一提到參數(shù),最熟悉的就是定義方法時(shí)有形參,然后調(diào)用此方法時(shí)傳遞實(shí)參。那么參數(shù)化類型怎么理解呢?顧名思義,就是將類型由原來的具體的類型參數(shù)化,類似于方法中的變量參數(shù),此時(shí)類型也定義成參數(shù)形式(可以稱之為類型形參),然后在使用/調(diào)用時(shí)傳入具體的類型(類型實(shí)參)
所以在接收參數(shù)的時(shí)候 我可以任意的將參數(shù)實(shí)例化(避免了參數(shù)寫死) 說大白話就是:我在項(xiàng)目a中的根節(jié)點(diǎn)是{1,2,3}那我在項(xiàng)目b中的根節(jié)點(diǎn)可能就要變成{a,b,c,d}
值得注意的是在你的實(shí)體類Result中 也要使用范型來接收數(shù)據(jù)即Result < T > 否則無效,甚至報(bào)錯(cuò)。到時(shí)候大家可以往底層的代碼看看 其實(shí)Subscriber是實(shí)現(xiàn)了觀察者Observer的方法的 在這里我不再深多解釋-雙手將鏈接奉上點(diǎn)擊-拋物線
好了 當(dāng)我的MySubscriber< T > 繼承Subscriber 我同樣也是實(shí)現(xiàn)了它內(nèi)部的方法
onStart()
onCompleted()
onError(Throwable errorMsg)
onNext(T t)
同時(shí) 我自己也寫了四個(gè)抽象的方法來作為整個(gè)抽象類的返回值 在此處 onNext(T t) 承載了返回的數(shù)據(jù) 到時(shí)大家可以根據(jù)自己(公司的)項(xiàng)目來更改 ,方法中 唯一必須要寫的就是
String jsonStr = ApiManager.objectMapper.writeValueAsString(result.getData());
此方法是jackjson中 將返回的json 轉(zhuǎn)化成字符串的形式返回出去,在我的MainActivity中 我又自己寫了個(gè)ParseJsonUtil類 來處理返回的字符串(這樣很大問題解決了重復(fù)性) 可轉(zhuǎn)化集合 或者單個(gè)的實(shí)體 具體的可在log中打印出來 哦 對(duì)了 我的GoodVideoBean只是個(gè)樣品 沒有實(shí)例的數(shù)據(jù)返回 大家可以嘗試寫一下 假如在又不明白的可以加我的qq 2215719882 來詢問我
項(xiàng)目地址 SmithGao https://github.com/SmithGao/rxjava_retrofit3.0_okhttp