
1) 要使用这两个框架当然要先把这两个框架的包导进来:这里可以看到还导入了RxBinding 的包,这是为了使用防抖功能而导入的,同时因为是开发 Android,因此除了导入 RxJava 还需导入 RxAndroid,否则所需的 API 是不完整的,RxJava占所需代码的 80%,RxAndroid 占20%,只有把这两部分一起导入,才是我们完整的API,例如我们在切换线程时,最经常用到的 AndroidSchedulers.mainThread(),就是 RxAndroid包里的。
// 依赖RxAndroid 2X 的依赖库
// 增加RxJava 2X 的依赖库
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.0.7'
// OkHttp相关
implementation 'com.facebook.stetho:stetho:1.4.2'
implementation 'com.facebook.stetho:stetho-okhttp3:1.4.2'
// 网络请求相关
implementation "com.squareup.retrofit2:retrofit:2.4.0"
implementation "com.squareup.retrofit2:retrofit-mock:2.4.0"
implementation "com.squareup.retrofit2:converter-gson:2.8.2"
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
implementation "com.squareup.retrofit2:converter-scalars:2.4.0"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
implementation "com.squareup.retrofit2:converter-gson:2.8.2"
implementation "com.google.code.gson:gson:2.8.2"
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1' // 操作功能防抖
2)使用 Retrofit 请求网络首先要写网络的请求接口,以及给这个接口打上注解(包括请求方式,地址,以及传参等)注意这里返回的是一个 Observable(被观察者)而我之前手写 Retrofit 的文章里返回的是一个 okHttp 的 Call。
public interface WanAndroid {
//总数据
@GET("project/tree/json")
Observable<ProjectBean> getProject();
//Item数据
@GET("project/list/{pageIndex}/json")
Observable<ProjectItem>getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);
}
3)接下来就是对 Retrofit对象 构建的封装,因为 Retrofit 是通过 okHttp 请求网络的,因此,这里其实也是对 okHttp 的封装。最后还封装了一个 RxJava 的线程切换方法,通过这个方法结合 compose 操作符就可以给上游分配到 io 异步线程,下游分配到 Android 主线程:
//设置BaseUrl,这部发将拼接到上一步注解的前半部分
public static String BASE_URL = "https://www.wanandroid.com/";
public static void setBaseUrl(String baseUrl) {
BASE_URL = baseUrl;
}
/**
* 根据各种配置创建出Retrofit
*
* @return 返回创建好的Retrofit
*/
public static Retrofit getOnlineCookieRetrofit() {
// OKHttp客户端
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
// 各种参数配置
OkHttpClient okHttpClient = httpBuilder
.addNetworkInterceptor(new StethoInterceptor())
.readTimeout(10000, TimeUnit.SECONDS)
.connectTimeout(10000, TimeUnit.SECONDS)
.writeTimeout(10000, TimeUnit.SECONDS)
.build();
return new Retrofit.Builder().baseUrl(BASE_URL)
// TODO 请求用 OKhttp
.client(okHttpClient)
// TODO 响应RxJava
// 添加一个json解析的工具
.addConverterFactory(GsonConverterFactory.create(new Gson()))
// 添加rxjava处理工具
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
//线程切换封装
public static <UD> ObservableTransformer<UD,UD> rxud(){
return new ObservableTransformer<UD, UD>() {
@Override
public ObservableSource<UD> apply(Observable<UD> upstream) {
//上游分配异步线程
return upstream.subscribeOn(Schedulers.io())
//下游分配主线程
.observeOn(AndroidSchedulers.mainThread())
.map(new Function<UD, UD>() {
@Override
public UD apply(UD ud) throws Exception {
Log.d("---", "apply: 我监听到你了,居然再执行");
return ud;
}
});
}
};
}
4)当然还要定义返回数据的 bean 类,我这里定义了两个 ProjectBean ,ProjectItem,就是一些基本的 set & get,这里省略不写。
5)使用的时候跟使用 Retrofit 时一样,先获得 第 2) 步 定义的接口对象,通过接口对象请求网络,通过 RxJava 操作返回的数据:
//获取全部数据
private void getProjectData() {
disposable = api.getProject()
.compose(HttpUtil.rxud())//切换线程
.subscribe(new Consumer<ProjectBean>() {
@Override
public void accept(ProjectBean projectBean) throws Exception {
Log.e("---", projectBean.toString());
}
});
}
可以看到这里使用了一个 Disposable 来接收操作完数据的结果,Disposable 的提供一个中断的作用,可以利用这个变量进行中断操作,当 APP 在关闭时,如果后台仍然持有Context 对象继续操作数据,这就会引发内存泄露,因此需要通过这个变量来防止内存泄漏:在onDestory 中断操作数据
@Override
protected void onDestroy() {
super.onDestroy();
if (disposable != null) {
if (!disposable.isDisposed()) {
disposable.dispose();
}
}
}
6)当出现网络嵌套的情况,可以使用 flatMap 操作符解决,flatMap 的作用是把数据处理完之后又封装成一个被观察者继续传给下游.。同时在这里使用了防抖(指的是指定时间内允许用户操作指定次数某控件):
//使用防抖+网络嵌套问题
//这里第一次层级尝试使用map操作符,但是效果不佳,查看map/flatMap源码:
//public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)
//public final <R> Observable<R> map(Function<? super T, ? extends R> mapper)
//可以看到flatMap操作符的Function的第二个入参(下游)是个被观察者,将这个被观察者作为下一步操作的上游
//而map的第二个入参是没有限制的泛型,
//总结:fltaMap 与 map 的区别是fltaMap 让用户操作完成之后又封装成一个被观察者继续向下传递
private void getDataByView() {
Button btnNet = findViewById(R.id.btn_net);
disposable = RxView.clicks(btnNet)
.throttleFirst(2, TimeUnit.SECONDS)//2s-允许点击一次
.observeOn(Schedulers.io())
.flatMap(
new Function<Object, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Object o) throws Exception {
return api.getProject();
}
})
.flatMap(
new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {
@Override
public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
return Observable.fromIterable(projectBean.getData());
}
})
.flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
@Override
public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
return api.getProjectItem(1, dataBean.getId());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ProjectItem>() {
@Override
public void accept(ProjectItem projectItem) throws Exception {
}
});
}
7)map操作符:作用是将上游的数据传再到下游观察者之前进行一次操作,转换成用户所需要的类型后再传给观察者,因此观察者接收到的上游就是被 map 转换之后的下游:
//获取全部数据
private void getProjectMap() {
disposable = api.getProject()
.compose(HttpUtil.rxud())//切换线程
//注意这里上游是 ProjectBean,提供给下游观察者的是 String
.map(new Function<ProjectBean, String>() {
@Override //这里返回的 String 提供给下游观察者
public String apply(ProjectBean projectBean) throws Exception {
return null;
}
})
//观察者接收到 map 返回的 String
.subscribe(new Consumer<String>() {
@Override
public void accept(String str) throws Exception {
Log.e("---", str);
}
});
}
8)**doOnNext操作符:在观察者的 next 操作之前先执行这个方法,一般用在一连续的操作(比如注册后显示UI,紧接着跳转登录)map 是在上游传给下游时进行一次拦截,而 doOnNext 则是在下游往上游回传时进行拦截:
//doOnNext练习
//doOnNext:就是在拿到结果交给订阅者之前截断,处理完成后再交给订阅者的Next操作
//map操作是在数据发送数据时,上游与下游之间截断
//doOnNext 是在拿到数据后,下游往上游回传时截断
private void getDataByNext(){
disposable = api.getProject()
.compose(HttpUtil.rxud())
.doOnNext(new Consumer<ProjectBean>() {
@Override
public void accept(ProjectBean projectBean) throws Exception {
Log.e("---","先执行这里");
}
})
.subscribe(new Consumer<ProjectBean>() {
@Override
public void accept(ProjectBean projectBean) throws Exception {
Log.e("---","后执行这里");
}
});
}
本篇主要以使用为主,RxJava 的原理性将在下篇文章讲解,希望对你有所帮助~
网友评论