开门见山,本文主要记录利用RxJava和Retrofit设计网络请求组件的基本配置,需要做如下准备
一.定义网络请求方法的接口文件:ApiService(名字随意哈)
接口文件定义了各个请求方法,请求方式及参数类型均以注解形式标识,示例文件仅描述了两种常用的请求方式(POST 和 GET)及参数注解方式,相关注意事项已经做了标识
/**
* 重要的事情说三遍:ApiService 必须是接口,ApiService 必须是接口,ApiService 必须是接口
* Created by cuiyan on 16-10-18.
*/
public interface ApiService {
/*************************GET 请求方式*************************/
/**
* ApiConstants.QQ_SPORT_API 请求接口地址api(相对路径)
* 域名部分会在构建Retrofit时设置
* 返回Observable对象(内部包装了Call实例),订阅(subscribe)执行时会调用Call.execute()方法发送网络请求。
*/
@GET(ApiConstants.QQ_SPORT_API)
Observable getQQSportNews(@Query("baid") String baid, @Query("apikey") String apiKey);
@GET(ApiConstants.QQ_SPORT_API)
Observable getQQSportNews1(@QueryMap Map paramsMap);
/*************************POST 请求方式*************************/
/**
* @Body 注解参数均表示以实体形式提交请求数据
*/
@POST(ApiConstants.QQ_SPORT_API)
Observable getQQSportNews2(@Body NewsResult bodyParam);
/**
* @Field 或 @FieldMap 注解参数均表示以表单形式提交参数,相应的,
* 请求方法必须添加 @FormUrlEncoded 注解
*/
@FormUrlEncoded
@POST(ApiConstants.QQ_SPORT_API)
Observable getQQSportNews3(@Field("baid") String baid, @Field("apikey") String apiKey);
@FormUrlEncoded
@POST(ApiConstants.QQ_SPORT_API)
Observable getQQSportNews4(@FieldMap Map paramsMap);
}
二.ApiService实例构建,这一步工作内容比较多,包括Retrofit构建及配置,代码如下:
public class BaseServiceUtil {
private static final int DEFAULT_TIMEOUT = 10;
/**
@param serviceClass 网络请求接口描述文件类,步骤一中的ApiService.class或其他类似class
@return S S实例,即ApiService实例
*/
public static synchronized S createService(Class serviceClass) {
return createService(serviceClass, null);
}
public static S createService(Class serviceClass, String baseUrl) {
CommonInterceptor interceptor = new CommonInterceptor();
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
if (!TextUtils.isEmpty(baseUrl)) {
retrofitBuilder.baseUrl(baseUrl);
} else {
retrofitBuilder.baseUrl(BuildConfig.BASE_URL);
}
clientBuilder.interceptors().clear();
clientBuilder.interceptors().add(interceptor);
// 设置证书
// try {
// clientBuilder.sslSocketFactory(RqbTrustManager.getInstance().getSSLSocketFactory("BKS", R.raw.rqb_ssl));
// } catch (Exception e) {
// e.printStackTrace();
// }
OkHttpClient client = clientBuilder.build();
Retrofit retrofit = retrofitBuilder.client(client).build();
return retrofit.create(serviceClass);
}
}
这个工具类的功能是生成ApiService实例,利用ApiService实例就可以获取包装了Call实例的Observable对象喽。通过代码可以看到,中间环节做了不少工作,重点如下:
1.通过OkHttpClient.Builder生成OkHttpClient实例并设置超时时间及拦截器interceptor(此处重点)
2.通过Retrofit.Builder及OkHttpClient 实例生成Retrofit实例。构建过程中Retrofit.Builder设置了Gson转换器,通过addCallAdapterFactory方法设置了RxJava2CallAdapterFactory(很重要),既然重要就看一看这个方法
/**
* Add a call adapter factory for supporting service method return types other than {@link Call}.
*/
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
api的描述翻译过来大概就是:添加了call adapter factory后,service中的方法可以返回除了Call以外的其他类型对象。而service 对应的就是我们的ApiService。也就是说只有设置了RxJava2CallAdapterFactory之后,
我们才能在ApiService中返回Observable对象
3.通过Retrofit实例生成ApiService实例,有了这个实例就能调用其定义的方法拿到Observable对象
interceptor之所以是我们重点关注的对象,是因为我们可以通过interceptor拦截请求,并做一些处理,例如添加header、添加公共参数等
RxJava2CallAdapterFactory这个类在另一片文章 Android 利用RxJava和Retrofit搭建网络请求组件——监听回调及部分源码解析中有所提及,它是Retrofit支持RxJava观察者模式的核心,我们再重温一下RxJava2CallAdapterFactory的核心方法
@Override
public Object adapt(Call call) {
************************************************重点*****************************************************
Observable> responseObservable = isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call);
*********************************************************************************************************
Observable> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
看到没有,adapt方法返回了observable对象,这个observable对象的生成过程在Android 利用RxJava和Retrofit搭建网络请求组件——监听回调及部分源码解析中也有所提及,可看一下源码,不再赘述。说来说去,虽然知道它生成了observable对象,但怎么生成的?好吧,不卖关子了,简单介绍一下,就看看Retrofit生成ApiService实例做了些什么好了,直接看前文提到的Retrofit的create方法
public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod
定位到倒数第四行:return serviceMethod.callAdapter.adapt(okHttpCall);这个callAdapter就是我们通过Retrofit.Builder addCallAdapterFactory ()方法设置的Factory,而我们设置的恰恰是RxJava2CallAdapterFactory,RxJava2CallAdapterFactory的adapt方法上面已经看过了。怎么样,逐渐清晰了,不是吗?
写到这,我们已经大概知晓了Retrofit部分使用及配置,通过ApiService实例也可以拿到封装了Call实例的Observable对象,就差Subscriber了,其实这部分内容在Android 利用RxJava和Retrofit搭建网络请求组件——监听回调及部分源码解析中已经做过阐述,不再赘述。
截止现在,能够发起网络请求的Observable和订阅者Subscriber都有了,就差“发射器了”,继续往下看发射器
public class BaseController {
/**
* @param subscriber 订阅者
*/
@SuppressWarnings("unchecked")
public static synchronized void sendRequest(final NetRequestSubscriber subscriber, Observable observable) {
observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(subscriber);
}
/**
* @param activity 用于与observable绑定,activity生命周期结束时,自动取消订阅
* @param observable 被观察者
* @param subscriber 订阅者
*/
@SuppressWarnings("unchecked")
public static synchronized void sendRequest(RxActivity activity, final NetRequestSubscriber subscriber, Observable observable) {
observable.subscribeOn(Schedulers.io())
.compose(activity.bindToLifecycle()) //防止内存泄漏,activity生命周期结束后取消订阅
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
/**
* @param fragment 用于与observable绑定,fragment生命周期结束时,自动取消订阅
* @param subscriber 订阅者
*/
@SuppressWarnings("unchecked")
public static synchronized void sendRequest(RxFragment fragment, final NetRequestSubscriber subscriber, Observable observable) {
observable.compose(fragment.bindToLifecycle()) //防止内存泄漏,fragment生命周期结束后取消订阅
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
}
发射器没什么东西,基本用法而已,我们只看一下Observable的订阅方法,以简单便了一下Observable是如何被订阅及网络请求如何发出的。
@SchedulerSupport(SchedulerSupport.NONE)
@Override
public final void subscribe(Observer super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
try {
observer = RxJavaPlugins.onSubscribe(this, observer);
ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");
subscribeActual(observer);
} catch (NullPointerException e) { // NOPMD
throw e;
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// can't call onError because no way to know if a Disposable has been set or not
// can't call onSubscribe because the call might have set a Subscription already
RxJavaPlugins.onError(e);
NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS");
npe.initCause(e);
throw npe;
}
}
定位到subscribeActual(observer)方法的调用,关于这个observer,其实例化在前述代码RxJava2CallAdapterFactory的adapt方法中可以看到,深入方法继续查看即可知晓,Android 利用RxJava和Retrofit搭建网络请求组件——监听回调及部分源码解析中也有较为详细的描述,可参阅。查看该observer的subscribeActual方法即可知道,被订阅后是调用了call.enqueue(具体实现方式可自行查阅源码或本人有时间时统一对细节及流程做相关阐述)来发送网络请求的:observer.subscribe --->observer.subscribeActual --->call.enqueue
至此Observable、订阅者Subscriber和发射器都有了,实战一下,实例代码通过获取腾讯体育NBA资讯数据演示该网络请求组件使用方法
private void getNews() {
NetRequestSubscriber subscriber = new NetRequestSubscriber<>(new NetRequestCallback() {
@Override
public void onStart() {
setContentState(STATE_NET_PROGRESS);
}
@Override
public void onSuccess(@NonNull NewsResult newsResult) {
if (newsResult.getData() != null && newsResult.getData().size() > 0) {
setContentState(STATE_DATA_CONTENT);
newsAdapter.updateDataList(newsResult.getData());
} else {
setContentState(STATE_DATA_EMPTY);
}
}
@Override
public void onResultNull() {
setContentState(STATE_NET_ERROR);
}
@Override
public void onError(Throwable throwable) {
setContentState(STATE_NET_ERROR);
}
@Override
public void onCancel() {
super.onCancel();
}
@Override
public void onFinish() {
super.onFinish();
}
}, this);
Observable observable = BaseServiceUtil.createService(ApiService.class, ApiConstants.JUHE_BASE_URL).getQQSportNews("69", Constant.JUHE_API_KEY);
BaseController.sendRequest(this, subscriber, observable);
}
本篇就写到这里,后续有空介绍一下拦截器的用法
Subscriber用法请参考:Android 利用RxJava和Retrofit搭建网络请求组件——监听回调及部分源码解析
完整示例:https://github.com/670832188/TestApp