公司的一个项目中已经采用了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中这样就不用写多余的代码。