公司的一個項目中已經採用了Retrofit加RxJava的作爲網絡請求框架,強大的框架所以替換了那麼久決定記錄一下我的實踐過程。
第一步,觀察服務器返回的結果定義返回結構實體類
{
"errno": 0,
"errmsg": "操作成功",
"data": []
}
所以我們可以定義個NetResponse< T >來作爲一次服務器返回結果實體類其中的T是對應返回json中的data字段,可以是一個對象或者是一個列表結果,所以定義一個實體類出來。
public class NetResponse<T> {
private String errno;
private String errmsg;
private T data;
}
第二步,初始化Retrofit
我們可以查看一下Square.Retrofit 官方對應的文檔介紹,首先我們需要一個interface來存放接口請求地址,那麼我們跟着文檔的步驟來
public interface UserService {
/**
* 登錄
*/
@FormUrlEncoded
@POST("/login/")
Observable<NetResponse<UserInfo>> doLogin(@Field("account") String account, @Field("pwd") String password);
}
這裏我們簡單的舉例爲用戶登錄的過程,因爲這是一個post請求所以按文檔需求我們使用了FormUrlEncoded和Field註釋字段。那如果是get請求呢?這裏我也舉個例子來表示get請求<這個例子是Retrofit的官方文檔例子>
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
這樣我們就懂了 如何使用Retrofit來實現get/post請求操作了。定義完了請求interface後我們該下一步初始化Retrofit了,因爲我項目中採用的是Fastjson作爲json解析工具,這裏需要先封裝一個FastConverterFactory,爲什麼呢?因爲Retrofit支持自定義Json解析類封裝類似自帶的Gson解析:
addConverterFactory(GsonConverterFactory.create())
所以我們也自己定義一個ConverterFactory來作爲FastJson解析類。
final class FastResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private Type type;
public FastResponseBodyConverter(Type type) {
this.type = type;
}
@Override
public T convert(ResponseBody value) throws IOException {
BufferedSource bufferedSource = Okio.buffer(value.source());
String tempStr = bufferedSource.readUtf8();
bufferedSource.close();
LogUtil.w("FastResponseBodyConverter", "-- FastJsonRequestResponse = " + tempStr);
return JSON.parseObject(tempStr, type);
}
}
定義一個FastResponseBodyConverter來將json解析過程寫在convert方法中
public class FastConverterFactory extends Converter.Factory {
public static FastConverterFactory create() {
return new FastConverterFactory();
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new FastResponseBodyConverter<>(type);
}
}
再定義一個FastConverterFactory來初始化Fastjson解析,這樣我們使用過程中不需要關心解析過程了,直接可以衝NetResponse中getT()方法得到我們想要的結果。
所以Retrofit的初始化過程我把定義了一個獨有的類。
public class AppRetrofit extends BaseRetrofit {
private AppService mService;
private Retrofit mRetrofit;
public AppService getService() {
if (null == mService) {
mService = getRetrofit().create(AppService.class);
}
return mService;
}
public Retrofit getRetrofit() {
if (null == mRetrofit) {
mRetrofit = new Retrofit.Builder()
.client(getOKHttpClient())
.baseUrl(BaseRetrofit.APP_URL)
.addConverterFactory(FastConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
return mRetrofit;
}
}
需要注意的是一定要加入下面這句代碼才能支持RxJava。
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
其中的BaseRetrofit的完成類如下:
public class BaseRetrofit {
private static final String TAG = "BaseRetrofit";
/**
* http請求成功
*/
public static final String HTTP_SUCCESS = "0";
public static final String USER_URL = "app_server_url";
/**
* 返回OkHttp配置
*/
public OkHttpClient getOKHttpClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
LogUtil.e("Retrofit", message);
}
});
HttpHeaderInterceptor headerInterceptor = new HttpHeaderInterceptor();
return new okhttp3.OkHttpClient.Builder()
.addNetworkInterceptor(interceptor)
.addNetworkInterceptor(headerInterceptor)
.build();
}
/**
* 請求結果轉換
*/
public final Observable.Transformer mTransformer = new Observable.Transformer() {
@Override
public Object call(Object observable) {
return ((Observable) observable)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1() {
@Override
public Object call(Object response) {
return _flatResponse((NetResponse<Object>) response);
}
});
}
};
/**
* 將返回的數據結果直接轉成想要的數據
*/
public final <T> Observable<T> _flatResponse(final NetResponse<T> response) {
return Observable.create(new Observable.OnSubscribe<T>() {
@Override
public void call(Subscriber<? super T> subscriber) {
if (!subscriber.isUnsubscribed()) {// 如果已經被回收的Subscribe的話就直接跳過
if (HTTP_SUCCESS.equals(response.getErrno())) {// 請求成功...
subscriber.onNext(response.getData());
subscriber.onCompleted();
} else {
LogUtil.e(TAG, "--- Retrofit request error ..........");
subscriber.onError(new ApiException(response.getErrno(), response.getErrmsg()));
}
}
}
});
}
}
其中我們還是需要解釋一下Observable.Transformer對象的mTransformer,他的作用就是代碼複用功效作用就是將我們返回的結果Observable< NetResponse< T > >轉換成Observable跟操作符flatmap的效果類似,不同的是Transformer可以一開始就執行而不像flatmap需要等subscribe之後才調用,所以轉換的話還是推薦使用Transformer類來解決,可以參考這篇文章避免打斷鏈式結構:使用.compose( )操作符
第三步,調用。
public class UserNetRetrofit extends UserRetrofit {
/**
* 登錄
*/
public Observable<UserInfo> doLogin(String account, String password) {
return getService().doLogin(account, password).compose(mTransformer);
}
}
我們這裏再一次把定義一個可見的類,把一切操作都寫在這裏面並且返回一個個Observable< T >給我們需要的View層自行拿取就好了。
所以代碼的調用如下:
final UserNetRetrofit loginRetrofit = new UserNetRetrofit();
Subscription subscription = loginRetrofit.doLogin(name, pwd)
.subscribe(new Action1<UserInfo>() {
@Override
public void call(UserInfo info) {
// 拿到UserInfo對象自行操作
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable e) {
// 一次請求操作失敗處理
}
});
BaseRetrofit.addSubscription(context, subscription);
如果你項目中採用的MVP模式可以把這段代碼寫到presenter層中,然後在call方法中分別回調成功或者失敗到view層,代碼看起來比較解耦不會很雜,ps:這裏並沒有那麼處理。
最後,注意點:
是不是發現了addSubscription這是什麼方法,Retrofit並沒有提供這個東西。對,這是自己寫的。
/**
* 存放Retrofit請求
*/
public CompositeSubscription mCompositeSubscription;
public void addSubscription(Subscription subscription) {
if (null != mCompositeSubscription) {
mCompositeSubscription.add(subscription);
}
}
就是這麼個東西,定義一個CompositeSubscription對象用於存放每一次的請求,爲了就是怕請求還沒成功的時候界面finish後未能釋放RxJava操作導致的內存泄露威脅。
@Override
protected void onDestroy() {
//關閉界面上的請求
if (null != mCompositeSubscription) {
mCompositeSubscription.unsubscribe();
}
super.onDestroy();
}
這樣一次完整的請求封裝就好了, 可以把一些公用的方法抽取放到BaseFragment或者BaseActivity中這樣就不用寫多餘的代碼。