我目前在Android上使用RxJava与Kotlin,但我遇到了问题,我无法使用toBlocking()解决问题。
我在员工服务中有方法,它返回一个Observable>:
fun all(): Observable<List<Employee>>
这一切都很好,因为只要员工发生变化,这个Observable就会发布新的员工列表。但我想从员工那里生成PDF文件,这显然不是每次员工变更都需要运行的。另外,我想从我的PDF生成器方法返回Completable
个对象。我想在我的PDF中添加标题,然后遍历员工并计算每个员工的工资,这也会返回一个Observable,这就是我现在使用toBlocking的地方。我目前的做法是:
private fun generatePdf(outputStream: OutputStream): Completable {
return employeeService.all().map { employees ->
try {
addHeaderToPDF()
for (i in employees) {
val calculated = employeeService.calculateWage(i.id).toBlocking().first()
// Print calculated to PDF....
}
addFooterToPDF()
return @map Completable.complete()
}
catch (e: Exception) {
return @map Completable.error(e)
}
}.first().toCompletable()
有没有办法让这个代码使用RxJava更清洁?
提前致谢!
答案 0 :(得分:2)
免责声明:此答案正在进行中。
基本前提:如果您在流中有blocking
,那么您做错了。
注意:没有州必须离开可观察的lambda。
输入是员工流。对于每个员工,您需要获得一份工资。让我们把它变成一个流。
/**
* @param employeesObservable
* Stream of employees we're interested in.
* @param wageProvider
* Transformation function which takes an employee and returns a [Single] of their wage.
* @return
* Observable stream spitting individual [Pair]s of employees and their wages.
*/
fun getEmployeesAndWagesObservable(
employeesObservable: Observable<Employee>,
wageProvider: Function<Employee, Single<Int>>
): Observable<Pair<Employee, Int>>? {
val employeesAndWagesObservable: Observable<Pair<Employee, Int>>
// Each Employee from the original stream will be converted
// to a Single<Pair<Employee, Int>> via flatMapSingle operator.
// Remember, we need a stream and Single is a stream.
employeesAndWagesObservable = employeesObservable.flatMapSingle { employee ->
// We need to get a source of wage value for current employee.
// That source emits a single Int or errors.
val wageForEmployeeSingle: Single<Int> = wageProvider.apply(employee)
// Once the wage from said source is loaded...
val employeeAndWageSingle: Single<Pair<Employee, Int> = wageForEmployeeSingle.map { wage ->
// ... construct a Pair<Employee, Int>
employee to wage
}
// This code is not executed now. It will be executed for each Employee
// after the original Observable<Employee> starts spitting out items.
// After subscribing to the resulting observable.
return@flatMapSingle employeeAndWageSingle
}
return employeesAndWagesObservable
}
订阅时会发生什么:
重复这一过程,直到employeesObservable
信号onComplete
或其他内容失败并显示onError
。
二手经营者:
嘿,你是如何将它与你的代码挂钩的:
fun doStuff() {
val employeesObservable = employeeService.all()
val wageProvider = Function<Employee, Single<Int>> { employee ->
// Don't listen to changes. Take first wage and use that.
employeeService.calculateWage(employee.id).firstOrError()
}
val employeesAndWagesObservable =
getEmployeesAndWagesObservable(employeesObservable, wageProvider)
// Subscribe...
}
二手经营者:
请勿订阅,请致电
val blockingIterable = employeesAndWagesObservable.blockingIterable()
blockingIterable.forEach { ... }
以同步方式处理每个项目。坐下来,找出后续步骤,观看演示文稿,阅读示例。
.map
每个Pair<Employee, Int>
到一些抽象的PDF构建块。Observable.fromCallable { ... }
将页眉和页脚打印机转换为Observables,让它们返回PDF构建块。Observable.concat(headerObs, employeeDataObs, footerObs)
.subscribe
此结果并开始将PDF构建块写入PDF编写器。答案 1 :(得分:0)
我想出了这个:
return employeeService.all().first()
.doOnSubscribe { addHeaderToPDF() }
.flatMapIterable { it }
.flatMap { employeeService.calculateWage(it.id).first() }
.doOnNext { printEmployeeWage(it) }
.doOnCompleted { addFooterToPDF }
.toCompletable()
这是应该怎么做的? :)