
#RxJava +retrofit2實(shí)現(xiàn)安卓中網(wǎng)絡(luò)操作~
在安卓中想實(shí)現(xiàn)網(wǎng)絡(luò)操作有多種方式,可能許多沒有經(jīng)歷過團(tuán)隊(duì)開發(fā)的安卓工程師,經(jīng)常使用到的是第三方的云后臺(tái),但是其實(shí)它們的底層使用的也一定是安卓中網(wǎng)絡(luò)的通信框架,例如:volley,nohttp,okhttp等。
今天我們要介紹的retrofit2底層就是用的okhttp的通信方式,下面簡單介紹一下為什么寫這篇文章吧,在開發(fā)團(tuán)隊(duì)項(xiàng)目以前,我也和我小伙伴交流過,我說咱們一直采用第三方的云后臺(tái),你說咱們?cè)趺春驼嬲姆?wù)器做聯(lián)系啊,我們那個(gè)時(shí)候異口同聲的說不知道,后來在我做的第一個(gè)團(tuán)隊(duì)項(xiàng)目“黑大盒子”的時(shí)候,我就學(xué)習(xí)了okHttp,那個(gè)時(shí)候感覺很好用啊,代碼也挺簡潔的,直至后來在一次,和我學(xué)長的交流過程中了解了可以用RxJava +retrofit2實(shí)現(xiàn)網(wǎng)絡(luò)的通信,那個(gè)時(shí)候我真的是下了很大的功夫研究,結(jié)果是毫無頭緒,因?yàn)槟莻€(gè)時(shí)候,我對(duì)觀察者模式,和rxjava的系統(tǒng)的思想就是非常的不夠的。在后來我學(xué)習(xí)了觀察者模式,又一直在找rxjava的資料使我對(duì)這種網(wǎng)絡(luò)通信有了一定的了解。
使用RxJava +retrofit2實(shí)現(xiàn)網(wǎng)絡(luò)通信的優(yōu)勢(shì)
- 請(qǐng)求時(shí)間和返回時(shí)間短(性能上的優(yōu)勢(shì))
- 代碼簡介,已經(jīng)把封裝實(shí)現(xiàn)到了極致
毫不夸張的說,如果公司沒有自己的網(wǎng)絡(luò)操作的框架,采用這種方式一定是最佳選擇之一
RxJava的簡介
鏈接:https://github.com/ReactiveX/RxJava
RxJava采用的思想便是觀察者模式,可以異步實(shí)現(xiàn)實(shí)現(xiàn)我們的需求,簡單的說,RxJava并不是輪詢?nèi)z測(cè)被觀察的對(duì)象,而是當(dāng)被觀察的對(duì)象有任何舉動(dòng)的時(shí)候都會(huì)告訴我們,我們便可以根據(jù)這個(gè)消息決定要做什么處理。
retrofit2的簡介
鏈接:https://github.com/square/retrofit
retrofit這個(gè)庫的功能非常的強(qiáng)大,它可以直接向Gson添加依賴,解析我們返回的json數(shù)據(jù)非常的輕松,而且我們實(shí)現(xiàn)網(wǎng)絡(luò)操作也非常的便捷,非常輕松的就可以實(shí)現(xiàn)在工作線程請(qǐng)求網(wǎng)絡(luò)操作,在主線程實(shí)現(xiàn)對(duì)網(wǎng)絡(luò)操作結(jié)果的處理。
在這里我要非常正式的聲明一下,不是筆者懶,用兩句話,就把這么傳奇的兩個(gè)第三方開源庫就給介紹完了,而且本文主要的目的是教大家怎么用它們實(shí)現(xiàn)網(wǎng)絡(luò)操作,我接下來的文章會(huì)非常認(rèn)真的介紹,觀察者模式、RxJava、retrofit,這三方面的知識(shí)。
ps:我始終認(rèn)為,在你學(xué)習(xí)一個(gè)編程上的知識(shí)的時(shí)候,你最先要做的不是弄明白它,而是要用明白它,然后跟著代碼的邏輯走一遍,看看它是怎么實(shí)現(xiàn)的,然后可以看看人家的官方文檔,或者大神們的博客學(xué)習(xí)一下,最后我們還可以閱讀以下源碼,這樣學(xué)起來可能會(huì)輕松,也會(huì)比較高效。
RxJava +retrofit2的使用?。?!
第一步:在build.gradle中添加依賴
// RxJava Android 支持
compile 'io.reactivex:rxjava:1.1.6'
compile 'io.reactivex:rxandroid:1.2.1'
// Retrofit 網(wǎng)絡(luò)支持
compile 'com.squareup.retrofit2:retrofit:2.1.0'compile 'com.squareup.retrofit2:converter-gson:2.1.0'
// Gson 適配器
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
第二步:添加必要的權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
第三步:定義一個(gè)接口,實(shí)現(xiàn)網(wǎng)絡(luò)操作
這個(gè)類,是在我們主URL后面鏈上的字段,然后泛型的是要返回?cái)?shù)據(jù)我要將它解析成什么樣子,里面的參數(shù)就是post請(qǐng)求需要攜帶的參數(shù)了。
/**
* Created by lin_sir on 2016/6/29.網(wǎng)絡(luò)協(xié)議
*/
public interface Api {
@FormUrlEncoded
@POST("getCode")
Observable<ResponseModel_nolist> getCode(@Field("tel") String tel);
@FormUrlEncoded
@POST("register")
Observable<ResponseModel_nolist> register(@Field("tel") String tel, @Field("password") String password, @Field("code") String code);
}
第四步:實(shí)現(xiàn)剛才泛型的類
為了讓大家使用起來毫無難度,我就在這里把這個(gè)簡單的類也粘出來了
/**
* Created by lin_sir on 2016/7/7.結(jié)果中不帶有l(wèi)ist的網(wǎng)絡(luò)返回結(jié)果
*/
public class ResponseModel_nolist {
private int code;
private String msg;
private obj obj;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public com.example.lin_sir_one.tripbuyer.model.obj getObj() {
return obj;
}
public void setObj(com.example.lin_sir_one.tripbuyer.model.obj obj) {
this.obj = obj;
}
}
第五步:實(shí)現(xiàn)一個(gè)BASE_URL,以后我們的網(wǎng)絡(luò)操作走的url都是在這些url后面加字段
當(dāng)然我打星號(hào)的,都是我們公司后臺(tái)暴露出來的接口啦,雖然我們做了負(fù)載均衡,也做了防止別人攻擊的處理啦,但是在這里暴露出來好像也還是不太好~
/* Created by lin_sir on 2016/6/29.全局常量定義
*/
public class Constant {
public static final String BASE_URL = "http://xxx.xxx.xxx.xxx:8080/lxms-user/member/api/";
public static final String BASE_BUY_URL = "http://xxx.xxx.xxx.xxx:8080//lxms-user/buyer/api/";
public static final String BASE_SELL_URL = "http://xxx.xxx.xxx.xxx:8080/lxms-user/seller/api/";
}
第六步:實(shí)現(xiàn)一個(gè)Apiservice,這個(gè)類的作用就是實(shí)現(xiàn)我們的網(wǎng)絡(luò)操作的直接方式~
/**
* Created by lin_sir on 2016/7/7.調(diào)用api接口,獲取驗(yàn)證碼和注冊(cè)采用這個(gè)接口
*/
public class ApiService {
private Api mApi;
private Context mContext;
private static ApiService mInstance;
//-------- 存在內(nèi)存泄漏的寫法,如果傳入 Activity 的 Context,會(huì)導(dǎo)致 Activity 無法被回收-------------------
// private ApiService(Context mContext) {
// this.mContext = mContext;
// mApi = RetrofitClient.getClient(mContext).create(Api.class);
// }
//
// public static ApiService getInstance(Context mContext) {
// if (mInstance == null) {
// mInstance = new ApiService(mContext);
// }
// return mInstance;
// }
//------------------------------------------------------------------------------------------------
private ApiService() {
this.mContext = BaseApplication.get().getAppContext();
mApi = RetrofitClient.getClient(mContext).create(Api.class);
}
public static ApiService getInstance() {
if (mInstance == null) {
mInstance = new ApiService();
}
return mInstance;
}
/**
* 獲取驗(yàn)證碼
*/
public void getCode(HttpResultListener<Boolean> listener, final String tel) {
mApi.getCode(tel)
.map(new HttpResultFuncNoList())
.map(new Func1<String, Boolean>() {
@Override
public Boolean call(String s) {
if (s.equals("ok")) {
return true;
} else {
return false;
}
}
})
.subscribeOn(Schedulers.io())//在工作線程請(qǐng)求網(wǎng)絡(luò)
.observeOn(AndroidSchedulers.mainThread())//在主線程處理結(jié)果
.subscribe(new HttpResultSubscriber<>(listener));
}
private static class HttpResultSubscriber<T> extends Subscriber<T> {
private HttpResultListener<T> mListener;
public HttpResultSubscriber(HttpResultListener<T> listener) {
mListener = listener;
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
if (mListener != null) {
mListener.onError(e);
}
}
@Override
public void onNext(T t) {
if (mListener != null) {
mListener.onSuccess(t);
}
}
}
/**
* 對(duì)返回結(jié)果做統(tǒng)一處理,只有當(dāng)結(jié)果碼為 100 時(shí),才返回正常,否則返回錯(cuò)誤,不帶list的
*/
private class HttpResultFuncNoList implements Func1<ResponseModel_nolist, String> {
@Override
public String call(ResponseModel_nolist responseModel) {
if (responseModel.getCode() == NetworkException.REQUEST_OK) {
Log.i("lin", "---lin---> 目前沒發(fā)生錯(cuò)誤: " + responseModel.getCode());
return responseModel.getMsg();
} else {
Log.i("lin", "---lin---> 錯(cuò)誤代碼: " + responseModel.getCode());
throw new NetworkException(responseModel.getCode());
}
}
}
}
第七步:實(shí)現(xiàn)網(wǎng)絡(luò)操作的回調(diào)接口
/**
* Created by lin_sir on 2016/7/7.網(wǎng)絡(luò)操作的回調(diào)接口
*/
public interface HttpResultListener<T> {
void onSuccess(T t);
void onError(Throwable e);
}
第八步:實(shí)現(xiàn)retrifit2客戶端
在這個(gè)客戶端里面,我們不僅實(shí)現(xiàn)了Gson的適配器,也實(shí)現(xiàn)了Rxjava的適配器,還為我們的操作添加了主URL就可以了。
public class RetrofitClient {
/**
* 采用base_url
*/
public static Retrofit getClient(Context context) {
return new Retrofit.Builder()
.baseUrl(Constant.BASE_URL)
//.client(httpClient(context))
.addConverterFactory(GsonConverterFactory.create())//Gson 適配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())// RxJava 適配器
.build();
}
}
其實(shí)我們的網(wǎng)絡(luò)操作就已經(jīng)實(shí)現(xiàn)完了,如果我們代碼習(xí)慣比較好的話,可以把所有的服務(wù)器返回的狀態(tài)嗎放在一起進(jìn)行統(tǒng)一的處理。
統(tǒng)一處理后臺(tái)返回狀態(tài)碼的代碼:
/**
* Created by tc on 6/21/16. 網(wǎng)絡(luò)操作錯(cuò)誤
*/
public class NetworkException extends RuntimeException {
public static final int REQUEST_OK = 100;
public static final int REQUEST_FAIL = 101;
public static final int METHOD_NOT_ALLOWED = 102;
public static final int PARAMETER_ERROR = 103;
public static final int UID_OR_PWD_ERROR = 104;
public static final int SERVER_INTERNAL_ERROR = 105;
public static final int REQUEST_TIMEOUT = 106;
public static final int CONNECTION_ERROR = 107;
public static final int VERIFY_EXPIRED = 108;
public static final int NO_DATA = 109;
public NetworkException(int resultCode) {
this(getNetworkExceptionMessage(resultCode));
}
public NetworkException(String detailMessage) {
super(detailMessage);
}
/**
* 將結(jié)果碼轉(zhuǎn)換成對(duì)應(yīng)的文本信息
*/
private static String getNetworkExceptionMessage(int code) {
String message = "";
switch (code) {
case REQUEST_OK:
message = "請(qǐng)求成功";
break;
case REQUEST_FAIL:
message = "請(qǐng)求失敗";
break;
case METHOD_NOT_ALLOWED:
message = "請(qǐng)求方式不允許";
break;
case PARAMETER_ERROR:
message = "用戶不存在";
break;
case UID_OR_PWD_ERROR:
message = "用戶名或密碼錯(cuò)誤";
break;
case SERVER_INTERNAL_ERROR:
message = "服務(wù)器內(nèi)部錯(cuò)誤";
break;
case REQUEST_TIMEOUT:
message = "請(qǐng)求超時(shí)";
break;
case CONNECTION_ERROR:
message = "連接錯(cuò)誤";
break;
case VERIFY_EXPIRED:
message = "驗(yàn)證過期";
break;
case NO_DATA:
message = "沒有數(shù)據(jù)";
break;
case 110:
message = "該用戶已存在";
break;
default:
message = "未知錯(cuò)誤";
}
return message;
}
}
好了,我們已經(jīng)可以使用RxJava +retrofit2實(shí)現(xiàn)網(wǎng)絡(luò)操作了:
HttpResultListener<List<JourneyModel>> listener = new HttpResultListener<List<JourneyModel>>() {
@Override
public void onSuccess(List<JourneyModel> journeyModels) {
KLog.d("----lin----> 成功");
}
@Override
public void onError(Throwable e) {
KLog.d("----lin----> 失敗" + e.toString());
}
};
ApiService6.getInstance().route2(listener, "1");
到這里我們就已經(jīng)把網(wǎng)絡(luò)通信徹底的研究了一遍啦,雖然看起來稍微有一點(diǎn)點(diǎn)小復(fù)雜,但是我們要想的是,整個(gè)工程的網(wǎng)絡(luò)通信,我這點(diǎn)代碼就已經(jīng)都寫完了啊,以后用起來可就非常的方便啦。
在這里,我們對(duì)RxJava,Retrofit2已經(jīng)有了一個(gè)了解了,初步我們已經(jīng)會(huì)使用了這些知識(shí),在接下來的文章里,我不會(huì)再這么詳細(xì)的介紹它們的使用,而是要介紹它們的實(shí)現(xiàn)的原理,和它們思想上的一些東西。
聲明:以上內(nèi)容為linSir本人原創(chuàng),這些知識(shí)都是我的小手下tc孜孜不倦教給我的,哈哈哈,他的個(gè)人網(wǎng)站是:www.classtc.com ,里面也有許多和編程有關(guān)的知識(shí)~如果大家,對(duì)這些知識(shí)有什么疑問,可以留言,我會(huì)第一時(shí)間回復(fù)的。