
#RxJava +retrofit2實現(xiàn)安卓中網(wǎng)絡(luò)操作~
在安卓中想實現(xiàn)網(wǎng)絡(luò)操作有多種方式,可能許多沒有經(jīng)歷過團隊開發(fā)的安卓工程師,經(jīng)常使用到的是第三方的云后臺,但是其實它們的底層使用的也一定是安卓中網(wǎng)絡(luò)的通信框架,例如:volley,nohttp,okhttp等。
今天我們要介紹的retrofit2底層就是用的okhttp的通信方式,下面簡單介紹一下為什么寫這篇文章吧,在開發(fā)團隊項目以前,我也和我小伙伴交流過,我說咱們一直采用第三方的云后臺,你說咱們怎么和真正的服務(wù)器做聯(lián)系啊,我們那個時候異口同聲的說不知道,后來在我做的第一個團隊項目“黑大盒子”的時候,我就學(xué)習(xí)了okHttp,那個時候感覺很好用啊,代碼也挺簡潔的,直至后來在一次,和我學(xué)長的交流過程中了解了可以用RxJava +retrofit2實現(xiàn)網(wǎng)絡(luò)的通信,那個時候我真的是下了很大的功夫研究,結(jié)果是毫無頭緒,因為那個時候,我對觀察者模式,和rxjava的系統(tǒng)的思想就是非常的不夠的。在后來我學(xué)習(xí)了觀察者模式,又一直在找rxjava的資料使我對這種網(wǎng)絡(luò)通信有了一定的了解。
使用RxJava +retrofit2實現(xiàn)網(wǎng)絡(luò)通信的優(yōu)勢
- 請求時間和返回時間短(性能上的優(yōu)勢)
- 代碼簡介,已經(jīng)把封裝實現(xiàn)到了極致
毫不夸張的說,如果公司沒有自己的網(wǎng)絡(luò)操作的框架,采用這種方式一定是最佳選擇之一
RxJava的簡介
鏈接:https://github.com/ReactiveX/RxJava
RxJava采用的思想便是觀察者模式,可以異步實現(xiàn)實現(xiàn)我們的需求,簡單的說,RxJava并不是輪詢?nèi)z測被觀察的對象,而是當(dāng)被觀察的對象有任何舉動的時候都會告訴我們,我們便可以根據(jù)這個消息決定要做什么處理。
retrofit2的簡介
鏈接:https://github.com/square/retrofit
retrofit這個庫的功能非常的強大,它可以直接向Gson添加依賴,解析我們返回的json數(shù)據(jù)非常的輕松,而且我們實現(xiàn)網(wǎng)絡(luò)操作也非常的便捷,非常輕松的就可以實現(xiàn)在工作線程請求網(wǎng)絡(luò)操作,在主線程實現(xiàn)對網(wǎng)絡(luò)操作結(jié)果的處理。
在這里我要非常正式的聲明一下,不是筆者懶,用兩句話,就把這么傳奇的兩個第三方開源庫就給介紹完了,而且本文主要的目的是教大家怎么用它們實現(xiàn)網(wǎng)絡(luò)操作,我接下來的文章會非常認(rèn)真的介紹,觀察者模式、RxJava、retrofit,這三方面的知識。
ps:我始終認(rèn)為,在你學(xué)習(xí)一個編程上的知識的時候,你最先要做的不是弄明白它,而是要用明白它,然后跟著代碼的邏輯走一遍,看看它是怎么實現(xiàn)的,然后可以看看人家的官方文檔,或者大神們的博客學(xué)習(xí)一下,最后我們還可以閱讀以下源碼,這樣學(xué)起來可能會輕松,也會比較高效。
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"/>
第三步:定義一個接口,實現(xiàn)網(wǎng)絡(luò)操作
這個類,是在我們主URL后面鏈上的字段,然后泛型的是要返回數(shù)據(jù)我要將它解析成什么樣子,里面的參數(shù)就是post請求需要攜帶的參數(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);
}
第四步:實現(xiàn)剛才泛型的類
為了讓大家使用起來毫無難度,我就在這里把這個簡單的類也粘出來了
/**
* 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;
}
}
第五步:實現(xiàn)一個BASE_URL,以后我們的網(wǎng)絡(luò)操作走的url都是在這些url后面加字段
當(dāng)然我打星號的,都是我們公司后臺暴露出來的接口啦,雖然我們做了負(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/";
}
第六步:實現(xiàn)一個Apiservice,這個類的作用就是實現(xiàn)我們的網(wǎng)絡(luò)操作的直接方式~
/**
* Created by lin_sir on 2016/7/7.調(diào)用api接口,獲取驗證碼和注冊采用這個接口
*/
public class ApiService {
private Api mApi;
private Context mContext;
private static ApiService mInstance;
//-------- 存在內(nèi)存泄漏的寫法,如果傳入 Activity 的 Context,會導(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;
}
/**
* 獲取驗證碼
*/
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())//在工作線程請求網(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);
}
}
}
/**
* 對返回結(jié)果做統(tǒng)一處理,只有當(dāng)結(jié)果碼為 100 時,才返回正常,否則返回錯誤,不帶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ā)生錯誤: " + responseModel.getCode());
return responseModel.getMsg();
} else {
Log.i("lin", "---lin---> 錯誤代碼: " + responseModel.getCode());
throw new NetworkException(responseModel.getCode());
}
}
}
}
第七步:實現(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);
}
第八步:實現(xiàn)retrifit2客戶端
在這個客戶端里面,我們不僅實現(xiàn)了Gson的適配器,也實現(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();
}
}
其實我們的網(wǎng)絡(luò)操作就已經(jīng)實現(xiàn)完了,如果我們代碼習(xí)慣比較好的話,可以把所有的服務(wù)器返回的狀態(tài)嗎放在一起進行統(tǒng)一的處理。
統(tǒng)一處理后臺返回狀態(tài)碼的代碼:
/**
* Created by tc on 6/21/16. 網(wǎng)絡(luò)操作錯誤
*/
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)換成對應(yīng)的文本信息
*/
private static String getNetworkExceptionMessage(int code) {
String message = "";
switch (code) {
case REQUEST_OK:
message = "請求成功";
break;
case REQUEST_FAIL:
message = "請求失敗";
break;
case METHOD_NOT_ALLOWED:
message = "請求方式不允許";
break;
case PARAMETER_ERROR:
message = "用戶不存在";
break;
case UID_OR_PWD_ERROR:
message = "用戶名或密碼錯誤";
break;
case SERVER_INTERNAL_ERROR:
message = "服務(wù)器內(nèi)部錯誤";
break;
case REQUEST_TIMEOUT:
message = "請求超時";
break;
case CONNECTION_ERROR:
message = "連接錯誤";
break;
case VERIFY_EXPIRED:
message = "驗證過期";
break;
case NO_DATA:
message = "沒有數(shù)據(jù)";
break;
case 110:
message = "該用戶已存在";
break;
default:
message = "未知錯誤";
}
return message;
}
}
好了,我們已經(jīng)可以使用RxJava +retrofit2實現(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ò)通信徹底的研究了一遍啦,雖然看起來稍微有一點點小復(fù)雜,但是我們要想的是,整個工程的網(wǎng)絡(luò)通信,我這點代碼就已經(jīng)都寫完了啊,以后用起來可就非常的方便啦。
在這里,我們對RxJava,Retrofit2已經(jīng)有了一個了解了,初步我們已經(jīng)會使用了這些知識,在接下來的文章里,我不會再這么詳細(xì)的介紹它們的使用,而是要介紹它們的實現(xiàn)的原理,和它們思想上的一些東西。
聲明:以上內(nèi)容為linSir本人原創(chuàng),這些知識都是我的小手下tc孜孜不倦教給我的,哈哈哈,他的個人網(wǎng)站是:www.classtc.com ,里面也有許多和編程有關(guān)的知識~如果大家,對這些知識有什么疑問,可以留言,我會第一時間回復(fù)的。