引言
Retrofit 是一個(gè)用于 Android 和 Java 平臺(tái)的類型安全的,底層使用OkHttp實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求框架。Retrofit 通過將 API 抽象成 Java 接口而讓我們連接到 REST web 服務(wù)變得很輕松症杏。
RxJava 提供一套異步編程的 API,這套 API 是基于觀察者模式的,而且是鏈?zhǔn)秸{(diào)用的。
Protocol Buffers 是一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式胁附,可以用于結(jié)構(gòu)化數(shù)據(jù)串行化,或者說序列化滓彰。它很適合做數(shù)據(jù)存儲(chǔ)或 RPC 數(shù)據(jù)交換格式控妻。
主要講解如何使用各個(gè)庫封裝網(wǎng)絡(luò)請(qǐng)求,不講解各庫如何使用揭绑,具體可查看Rxjava2弓候、Retrofit2 、ProtoBuf他匪。
依賴
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'
implementation 'com.squareup.wire:wire-runtime:2.3.0-RC1'
implementation 'com.squareup.retrofit2:retrofit-adapters:2.5.0'
implementation 'com.squareup.retrofit2:converter-wire:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
其中RxAndroid是為優(yōu)雅地處理異步請(qǐng)求和解決線程調(diào)度問題菇存;Wire用于將請(qǐng)求結(jié)果轉(zhuǎn)換為實(shí)體類型,并且wire是生成ProtoBuf文件的一種诚纸,沒有用官方的protobuf生成java文件撰筷,主要是為了解決64k限制陈惰,減少生成java的代碼量畦徘,但需要注意的是wire生成的java文件需要判斷null,而官方的protobuf生成java文件是有默認(rèn)值的抬闯,無需判斷null井辆。
proto文件
在客戶端可能需要相關(guān)客戶端信息,例如設(shè)備信息溶握、設(shè)備類型杯缺,app信息、網(wǎng)絡(luò)信息等睡榆。
// 設(shè)備類型
enum PBDeviceType {
DEVICE_ANDROID = 0; // 安卓
DEVICE_IOS = 1; // 蘋果
DEVICE_PC = 2; // PC
}
// 設(shè)備
message PBDevice {
string deviceId = 1; // 設(shè)備ID
string deviceOs = 2; // 設(shè)備操作系統(tǒng)
string deviceModel = 3; // 設(shè)備模型
PBDeviceType deviceType = 4; // 設(shè)備類型萍肆,參考PBDeviceType
}
// 網(wǎng)絡(luò)類型
enum PBNetworkType {
NET_UNKNOWN = 0; // 未知網(wǎng)絡(luò)
NET_WIFI = 1; // WIFI
NET_2G = 2; // 2G網(wǎng)絡(luò)
NET_3G = 3; // 3G網(wǎng)絡(luò)
NET_4G = 4; // 4G網(wǎng)絡(luò)
}
// APP信息
message PBAppInfo {
string versionName = 1; // 應(yīng)用程序版本名
uint32 versionCode = 2; // 應(yīng)用程序版本號(hào)
PBNetworkType network = 3; // 網(wǎng)絡(luò)信息
PBDevice device = 4; // 設(shè)備信息
}
定義Request和Response
// 消息請(qǐng)求包
message PBRequest {
uint32 type = 1; // 消息類型
bytes messageData = 2; // 請(qǐng)求數(shù)據(jù)
uint64 timestamp = 3; // 客戶端時(shí)間戳
PBAppInfo appInfo = 4; // APP信息
}
// 消息響應(yīng)包
message PBResponse {
uint32 type = 1; // 消息類型
bytes messageData = 2; // 返回?cái)?shù)據(jù)
uint32 resultCode = 3; // 返回的結(jié)果碼
string resultInfo = 4; // 返回的結(jié)果消息提示文本(用于錯(cuò)誤提示)
}
使用命令生成相關(guān)的Java文件
java -jar ${wire_compiler} --proto_path=${protoPath} --java_out=${modelPath} $1
- wire_compiler:wire.jar的存放路徑
- protoPath:proto文件存放路徑
-
modelPath:生成java文件存放路徑
圖片.png
請(qǐng)求接口
定義一個(gè)Service的接口類,管理所有請(qǐng)求接口
public interface Service {
@POST("users/new")
Observable<Response<PBResponse>> sendMessage(@Body PBRequest request);
}
請(qǐng)求處理
定義一個(gè)RetrofitHandler類胀屿,處理retrofit的初始化和發(fā)送請(qǐng)求塘揣,該類使用靜態(tài)單例進(jìn)行初始化。
private Service mService; // 請(qǐng)求接口
private static String mServiceUrl; // 請(qǐng)求url
private static class Holder {
private static final RetrofitHandler INSTANCE = new RetrofitHandler();
}
private RetrofitHandler() {
init();
}
public static RetrofitHandler getInstance(String serviceUrl) {
mServiceUrl = serviceUrl;
return Holder.INSTANCE;
}
retrofit的初始化宿崭,使用wire的factory進(jìn)行數(shù)據(jù)轉(zhuǎn)換亲铡,使用rxjava2進(jìn)行適配。
private void init() {
assert mServiceUrl != null;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(mServiceUrl)
.client(createClient())
.addConverterFactory(WireConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
mService = retrofit.create(Service.class);
}
private OkHttpClient createClient() {
return new OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.connectionPool(new ConnectionPool(5, 1, TimeUnit.MINUTES))
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.build();
}
retrofit進(jìn)行接口調(diào)用發(fā)送請(qǐng)求
public Observable<PBResponse> send(final PBRequest request) {
return mService.sendMessage(request)
.map(new Function<Response<PBResponse>, PBResponse>() {
@Override
public PBResponse apply(Response<PBResponse> response) throws Exception {
if (response == null) {
return failed(request.type, 1001, "未知錯(cuò)誤");
}
if (response.code() != 200 || response.body() == null) {
return failed(request.type, response.code(), response.message());
}
return response.body();
}
});
}
private PBResponse failed(int type, int code, String info) {
return new PBResponse.Builder()
.type(type)
.resultCode(code)
.resultInfo(info)
.build();
}
返回處理
定義ApiResult的泛型返回模型,對(duì)返回?cái)?shù)據(jù)進(jìn)行二次處理
public class ApiResult<T extends Message> {
private int code; // 返回碼
private String message; // 返回信息
private T response; // 返回?cái)?shù)據(jù)
public ApiResult(int code, String message, T response) {
this.code = code;
this.message = message;
this.response = response;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public T getResponse() {
return response;
}
}
定義ApiCallback泛型回調(diào)處理類奖蔓,給業(yè)務(wù)層進(jìn)行相關(guān)的業(yè)務(wù)處理赞草,如刷新UI等。
public class ApiCallback<T extends Message> {
private boolean isDisposed = false; // 返回處理標(biāo)志
public boolean isDisposed() {
return isDisposed;
}
public void setDisposed(boolean disposed) {
isDisposed = disposed;
}
public void onStart() {
// 請(qǐng)求開始
}
public void onSuccess(T response) {
}
public void onFailure(int code, String message) {
}
public void onCompleted() {
// 請(qǐng)求完成
}
}
定義IRquest接口吆鹤,給業(yè)務(wù)端初始化相關(guān)客戶端信息
public interface IRequest {
String getVersionName();
Integer getVersionCode();
PBNetworkType getNetworkType();
PBDevice getDevice();
}
定義HttpManager類厨疙,使用單例進(jìn)行實(shí)例化
private static class Holder {
private static final HttpManager INSTANCE = new HttpManager();
}
private HttpManager() {
}
public static HttpManager getInstance() {
return HttpManager.Holder.INSTANCE;
}
定義一個(gè)初始化方法,可以在application進(jìn)行初始化
public void init(IRequest request, String url){
mRequest = request;
mHandler = RetrofitHandler.getInstance(url);
}
使用Rxjava2進(jìn)行返回處理
@SuppressLint("CheckResult")
public <T extends Message, P extends Message> Disposable request(final T request, final int messageType,
final Class<P> pClass, final ApiCallback<P> apiCallback) {
Observable observable = mHandler.send(buildBody(request, messageType)) // 發(fā)送請(qǐng)求
.map(new Function<PBResponse, ApiResult<? extends Message>>() {
@Override
public ApiResult<? extends Message> apply(PBResponse pbResponse) throws Exception {
return apiResult(pClass, pbResponse);
}
});
observable.doOnDispose(new Action() { // 業(yè)務(wù)端取消訂閱時(shí)調(diào)用
@Override
public void run() throws Exception {
apiCallback.setDisposed(true);
}
});
return toSubscribe(observable, new Consumer<ApiResult<P>>() {
@Override
public void accept(ApiResult<P> apiResult) throws Exception {
if (apiCallback == null || apiCallback.isDisposed()) return;
try {
if (apiResult.getCode() == 200) {
apiCallback.onSuccess(apiResult.getResponse());
} else {
apiCallback.onFailure(apiResult.getCode(), apiResult.getMessage());
}
} catch (Exception ex) {
apiCallback.onFailure(1004, "客戶端處理異常");
} finally {
apiCallback.onCompleted();
}
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
if (apiCallback == null || apiCallback.isDisposed()) return;
//客戶端本地的異常疑务,如斷網(wǎng)等
try {
apiCallback.onFailure(1005, "網(wǎng)絡(luò)連接錯(cuò)誤");
} catch (Exception e) {
} finally {
apiCallback.onCompleted();
}
}
}, new Action() {
@Override
public void run() {
if (apiCallback == null || apiCallback.isDisposed()) return;
//onCompleted will not be called when occurs network exception, like disconnected/timeout, replace invoking at onNext/onError
}
}, new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) {
if (apiCallback == null || apiCallback.isDisposed()) return;
apiCallback.onStart();
}
});
}
// 異步訂閱
private <T> Disposable toSubscribe(Observable<T> o, Consumer<T> onNext, Consumer<Throwable> onError, Action onComplete, Consumer<Disposable> onSubscribe) {
return o.subscribeOn(Schedulers.io())// io線程處理
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())// 主線程處理
.subscribe(onNext, onError, onComplete, onSubscribe);
}
使用
初始化
HttpManager.getInstance().init(new RequestInfo(), mServerUrl);
使用MVP或者M(jìn)VVM的架構(gòu)轰异,在P或者VM層調(diào)用請(qǐng)求
HttpManager.getInstance().request(new PBAppInfo.Builder().build(), 1001, PBResponse.class, new ApiCallback<PBResponse>() {
@Override
public void onSuccess(PBResponse response) {
super.onSuccess(response);
}
@Override
public void onFailure(int code, String message) {
super.onFailure(code, message);
}
});
github源碼地址:https://github.com/fomin-zhu/retrofit2