0. 环境:
电脑:Windows10
Android Studio: 2024.3.2
编程语言: Java
Gradle version:8.11.1
Compile Sdk Version:35
Java 版本:Java11
1. 写该篇文章的由来
上篇文章中,最后的例子:
// 缩进过多的示范 // clicks 传入view, 也就是button这个view。此处是使用viewBinding框架 // Button btn = findViewById(R.id.button); 此处传入btn也是一样的 RxView.clicks(binding.buttonRequest) .throttleFirst(2000, TimeUnit.MILLISECONDS) //防抖动,2秒内只响应第1次 .subscribe(new Consumer<Unit>() {//此处的Unit可以不用接收 @Override public void accept(Unit unit) throws Throwable { // 网络请求,获取项目http。与getProjectHttp() 函数一样 netApi.getProject() .compose(rxud()) .subscribe(new Consumer<ProjectBean>() { @Override public void accept(ProjectBean projectBean) throws Throwable { Log.i(TAG, "accept: " + projectBean); // 此处可以通过获得的projectBean,继续请求Item for (ProjectBean.DataDTO data : projectBean.getData()) { netApi.getProjectItem(1,data.getId()) .compose(rxud()) .subscribe(new Consumer<ItemBean>() { @Override public void accept(ItemBean itemBean) throws Throwable { Log.i(TAG, "accept: " + itemBean); } }); } } }); } });
如果最后for循环中,替换成调用netApi,则会造成缩进的代码太多、阅读困难的问题。
实际上,现在只有两个网络请求。当数量继续增加时,缩进的代码会更多。非常不优雅
2. 优化1.中的代码
先贴上最终代码:
// clicks 传入view, 也就是button这个view。此处是使用viewBinding框架
// Button btn = findViewById(R.id.button); 此处传入btn也是一样的
RxView.clicks(binding.buttonRequest)
.throttleFirst(2000, TimeUnit.MICROSECONDS) //防抖动,2秒内只响应第1次
.observeOn(Schedulers.io()) // 切换成子线程
.flatMap(new Function<Unit, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Unit unit) throws Throwable {
// 获取项目数据
return netApi.getProject();
}
})
.flatMap(new Function<ProjectBean, ObservableSource<ProjectBean.DataDTO>>() {
@Override
public ObservableSource<ProjectBean.DataDTO> apply(ProjectBean projectBean) throws Throwable {
// 迭代器,遍历projectBean中 List<Data> 的数据
return Observable.fromIterable(projectBean.getData());
}
})
.flatMap(new Function<ProjectBean.DataDTO, ObservableSource<ItemBean>>() {
@Override
public ObservableSource<ItemBean> apply(ProjectBean.DataDTO dataDTO) throws Throwable {
// 获取项目item的数据
return netApi.getProjectItem(1, dataDTO.getId());
}
})
.observeOn(AndroidSchedulers.mainThread()) // 切换到主线程,方便操作UI
.subscribe(new Consumer<ItemBean>() {
@Override
public void accept(ItemBean itemBean) throws Throwable {
// 最后得到 item,操作UI
Log.i(TAG, "accept: " + itemBean.toString());
}
})
;
其中代码对比:
第一个,获取项目信息的http的部分:
// 旧代码
.subscribe(new Consumer<Unit>() {//此处的Unit可以不用接收
@Override
public void accept(Unit unit) throws Throwable {
// 网络请求,获取项目http。与getProjectHttp() 函数一样
netApi.getProject()
·····
}
});
// 等价于
// 优化后的代码
.flatMap(new Function<Unit, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Unit unit) throws Throwable {
// 获取项目数据
return netApi.getProject();
}
})
第二个,for循环部分
// 旧代码
for (ProjectBean.DataDTO data : projectBean.getData()) {
····
}
// 等价于
// 优化后的代码
.flatMap(new Function<ProjectBean, ObservableSource<ProjectBean.DataDTO>>() {
@Override
public ObservableSource<ProjectBean.DataDTO> apply(ProjectBean projectBean) throws Throwable {
// 迭代器,遍历projectBean中 List<Data> 的数据
return Observable.fromIterable(projectBean.getData());
}
})
第三个,获取item信息的http的部分:
// 旧代码
netApi.getProjectItem(1,data.getId())
.compose(rxud())
···
// 等价于
//优化后的代码
.flatMap(new Function<ProjectBean.DataDTO, ObservableSource<ItemBean>>() {
@Override
public ObservableSource<ItemBean> apply(ProjectBean.DataDTO dataDTO) throws Throwable {
// 获取项目item的数据
return netApi.getProjectItem(1, dataDTO.getId());
}
})
最后的.subscribe是一样的。
比较难理解的部分,在于for循环等价于迭代器,也就是第二步。
稍微解释一下,ObservableSource对象可以往下一张卡片发多次对象。
通过Observable.fromIterable(projectBean.getData()); 就可以遍历projectBean.getData()(即List<Data>)数组中的所有数据。
下一张卡片,会一条一条收到数据,并且一条一条按业务逻辑处理。
这样就可以提高代码可阅读性,解决缩进过多的问题
3. 写在最后
.flatMap 稍微难理解,但是也稍微高级。
请多查阅资料,务必弄懂该函数。
你与其他程序员的差距,就在此刻体现。
请加油学习。
关于RxJava,可以查看我其他文章:
【安卓笔记】RxJava的使用+修改功能+搭配retrofit+RxView防快速点击:【安卓笔记】RxJava的使用+修改功能+搭配retrofit+RxView防快速点击-CSDN博客
【安卓笔记】RxJava之flatMap的使用:【安卓笔记】RxJava之flatMap的使用-CSDN博客
【安卓笔记】RxJava的onNextDo的使用:【安卓笔记】RxJava的doOnNext的使用-CSDN博客
【安卓笔记】RxJava的Hook机制,整体拦截器:https://blog.csdn.net/liosen/article/details/149467298