Rxjava操作符详解之转换操作符
RxJava操作符——转换操作符
在ReactiveX中转换操作时这样子描述的Transforming Observables : Operators that transform items that are emitted by an Observable,其含义就是将需要发射的Observable通过使用Transforming Operators这种操作相关的函数修饰符转换成真正需要发射的Observable。
转换操作符常见分类如下:
map操作符
map:transform the items emitted by an Observable by applying a function to each item。
map通过实现Function 接口中 apply方法将每一项所需要的发射Observable数据转化为相应实际所需的Observable。
原理作用图:
示例代码以及相关源码如下
private fun operatorsMap() =
Observable.just(10, 20, 30).map {
(it * 2).toString()
}.subscribe {
logIMessage("operatorsMap", it)
}
/**
* 运行结果:
* com.ypz.rxjavademo I/operatorsMap: 20
* com.ypz.rxjavademo I/operatorsMap: 40
* com.ypz.rxjavademo I/operatorsMap: 60
* 源码如下:
* */
/**
* Returns an Observable that applies a specified function to each item emitted
* by the source ObservableSource and emits the results of these function applications.
* @param <R> the output type
* @param mapper a function to apply to each item emitted by the ObservableSource
* @return an Observable that emits the items from the source ObservableSource, transformed by the specified function
*/
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}
/**
* A functional interface that takes a value and returns another value,
* possibly with a different type and allows throwing a checked exception.
*
* @param <T> the input value type
* @param <R> the output value type
*/
public interface Function<T, R> {
/**
* Apply some calculation to the input value and return some other value.
* @param t the input value
* @return the output value
* @throws Exception on error
*/
R apply(@NonNull T t) throws Exception;
}
结合示例代码以及运行结果可以的出map操作符将每一个需要发射数据通过apply的实现将元数据进行一些加工操作,将其转换为其他数据。
注意:map操作符中的实现时,应该采用一套针对相应业务场景的数学转换规则避免产生不可期望结果以及转换异常
flatMap操作符
flatMap:transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable。
flatMap作用:通过將每一个Observable变换为一组Observables,然后发射每一个Observable。
原理作用流程如下:
结合上图以及作用解析不难看出,flatMap的转换作用是将一些元数据进行加工操作,由于是merge操作所以在并发上先后顺序可能不一致,转换方法以及先后顺序会结合示例代码以及源码一起分析,相关代码如下:
private fun operatorsFlatMap() {
logIMessage("operators-flatMap", "直接转换")
Observable.just(1, 2, 3).flatMap {
Observable.just(it * 2 - 1)
}.subscribe {
logIMessage("operators-flatMap", "直接转换value:$it")
}
logIMessage("operators-flatMap", "直接转换加函数变换")
val function = Function<Int, Observable<Int>> {
value ->
logIMessage("operators-flatMap", "需要转换的Value:$value")
Observable.range(value * 10, 2)
}
val biFunction = BiFunction<Int, Int, Int> {
initValue, changeValue ->
logIMessage("operators-flatMap", "转换前数值:$initValue")
logIMessage("operators-flatMap", "转换后数值:$changeValue")
initValue + changeValue
}
just(1, 2, 3).observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.flatMap(function, biFunction)
.subscribe {
logIMessage("operators-flatMap", "直接转换加函数变换value:$it")}
}
/**
* 运行结果:
* com.ypz.rxjavademo I/operators-flatMap: 直接转换
* com.ypz.rxjavademo I/operators-flatMap: 直接转换value:1
* com.ypz.rxjavademo I/operators-flatMap: 直接转换value:3
* com.ypz.rxjavademo I/operators-flatMap: 直接转换value:5
* com.ypz.rxjavademo I/operators-flatMap: 直接转换加函数变换
* com.ypz.rxjavademo I/operators-flatMap: 需要转换的Value:1
* com.ypz.rxjavademo I/operators-flatMap: 转换前数值:1
* com.ypz.rxjavademo I/operators-flatMap: 转换后数值:10
* com.ypz.rxjavademo I/operators-flatMap: 直接转换加函数变换value:11
* com.ypz.rxjavademo I/operators-flatMap: 转换前数值:1
* com.ypz.rxjavademo I/operators-flatMap: 转换后数值:11
* com.ypz.rxjavademo I/operators-flatMap: 直接转换加函数变换value:12
* com.ypz.rxjavademo I/operators-flatMap: 需要转换的Value:2
* com.ypz.rxjavademo I/operators-flatMap: 转换前数值:2
* com.ypz.rxjavademo I/operators-flatMap: 转换后数值:20
* com.ypz.rxjavademo I/operators-flatMap: 直接转换加函数变换value:22
* com.ypz.rxjavademo I/operators-flatMap: 转换前数值:2
* com.ypz.rxjavademo I/operators-flatMap: 转换后数值:21
* com.ypz.rxjavademo I/operators-flatMap: 直接转换加函数变换value:23
* com.ypz.rxjavademo I/operators-flatMap: 需要转换的Value:3
* com.ypz.rxjavademo I/operators-flatMap: 转换前数值:3
* com.ypz.rxjavademo I/operators-flatMap: 转换后数值:30
* com.ypz.rxjavademo I/operators-flatMap: 直接转换加函数变换value:33
* com.ypz.rxjavademo I/operators-flatMap: 转换前数值:3
* com.ypz.rxjavademo I/operators-flatMap: 转换后数值:31
* com.ypz.rxjavademo I/operators-flatMap: 直接转换加函数变换value:34
* 源码如下:
* */
edulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) {
return flatMap(mapper, false);
}
public interface Function<T, R> {
/**
* Apply some calculation to the input value and return some other value.
* @param t the input value
* @return the output value
* @throws Exception on error
*/
R apply(@NonNull T t) throws Exception;
}
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <U, R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends U>> mapper,
BiFunction<? super T, ? super U, ? extends R> resultSelector) {
return flatMap(mapper, resultSelector, false, bufferSize(), bufferSize());
}
/**
* A functional interface (callback) that computes a value based on multiple input values.
* @param <T1> the first value type
* @param <T2> the second value type
* @param <R> the result type
*/
public interface BiFunction<T1, T2, R> {
/**
* Calculate a value based on the input values.
* @param t1 the first value
* @param t2 the second value
* @return the result value
* @throws Exception on error
*/
@NonNull
R apply(@NonNull T1 t1, @NonNull T2 t2) throws Exception;
}
结合第一个直接转换的示例代码以及相关运行结果源码中可以看到,其转换的核心是通过实现Function这一接口思维来实现对数据的转换的操作。
重点探讨第二种直接转换加函数变换的写法:结合示例代码和源码可以看到直接转换的核心还是通过Function这一个思维去实现的,而转换以及函数变换主用场景运用于:当业务场景不仅仅需要需要直接将元数据直接转换,并且在转换后准备发射数据的过程中,需要将元数据以及转换数据进行一个比对或者在进行一个函数操作来保证最终所需转换的发射数据是符合业务场景。从源码中可以得出函数变换是通过对BiFunction实现去达到结果,注意在函数变换中如果变换不符合正常代码运行的业务逻辑则会抛出异常终止整个事件流数据的发射,需要谨记在BiFunction中T1 T2 R分别代表转换前元数据、转换后元数据、发射最终所需的转换数据类型。
concatMap操作符
concatMap与flatMap类似,但是没有merge操作所以,顺序是能够保证一致也就是在并发线程中操作时线程是安全的。
在concatMap中为了保证线程安全的操作采用了concat操作避免了merge操作导致的并发问题。
其原理作用流程如下:
在其流程图中可以的出,采用了concat操作不管函数变换过程中发生了什么其数据发射都会依照原数据发射的顺序的流程来进行数据的发射。
private fun operatorsConcatMap() =
just(1, 2, 3).concatMap {
Observable.range(it * 10, 2)
}.subscribe {
logIMessage("operators-concatMap", "value$it")
}
/**
* 运行结果如下:
* com.ypz.rxjavademo I/operators-concatMap: value10
* com.ypz.rxjavademo I/operators-concatMap: value11
* com.ypz.rxjavademo I/operators-concatMap: value20
* com.ypz.rxjavademo I/operators-concatMap: value21
* com.ypz.rxjavademo I/operators-concatMap: value30
* com.ypz.rxjavademo I/operators-concatMap: value31
* 源码如下
* */
/**
* Returns a new Observable that emits items resulting from applying a function that you supply to each item
* emitted by the source ObservableSource, where that function returns an Observ