"kotlin и rx в android" Дмитрий Воронин (avito)
TRANSCRIPT
![Page 1: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/1.jpg)
Kotlin и Rx в Android
![Page 2: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/2.jpg)
Rx & Single Abstract Method
![Page 3: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/3.jpg)
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return s.hashCode();
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer i) {
System.out.println(i);
}
});
Java
![Page 4: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/4.jpg)
Rx & Single Abstract Methodpublic interface Func1<T, R> extends Function {
R call(T t);
}
![Page 5: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/5.jpg)
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return s.hashCode();
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer i) {
System.out.println(i);
}
});
Java
Observable.just("Hello, world!")
.map { s -> s.hashCode() }
.subscribe { i -> println(i) }
Kotlin
![Page 6: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/6.jpg)
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return s.hashCode();
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer i) {
System.out.println(i);
}
});
Java
Observable.just("Hello, world!")
.map { s -> s.hashCode() }
.subscribe { i -> println(i) }
Kotlin
![Page 7: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/7.jpg)
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map { s -> s.hashCode() }
.subscribe { i -> println(i) }
![Page 8: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/8.jpg)
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map { string -> string.hashCode() }
.subscribe { hashCode -> println(hashCode) }
![Page 9: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/9.jpg)
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map { it.hashCode() }
.subscribe { println(it) }
![Page 10: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/10.jpg)
Rx & High-Order functions
![Page 11: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/11.jpg)
Rx & High-Order functionsfun yourFunc(one: String, two: Func0<Int>)
![Page 12: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/12.jpg)
Rx & High-Order functionsfun yourFunc(one: String, two: () -> Int)
![Page 13: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/13.jpg)
Rx & High-Order functionsfun yourFunc(one: String, two: () -> Int)
yourFunc("Hi") { 1 }
![Page 14: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/14.jpg)
Rx & High-Order functionsObservable.combineLatest(one, two) { a, b -> a + b }
Observable.zip(one, two, three) { a, b, c -> a + b + c }
![Page 15: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/15.jpg)
Rx & Data types
![Page 16: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/16.jpg)
Rx & Data typesObservable.combineLatest(location, webResponse){ a, b -> Pair(a, b) }
.distinctUntilChanged()
.map { doSomething(it.first, it.second) }
![Page 17: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/17.jpg)
Rx & Data typesObservable.combineLatest(location, webResponse){ a, b -> LocationAndResponse(a, b)}
.distinctUntilChanged()
.map { doSomething(it.location, it.response) }
![Page 18: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/18.jpg)
Rx & Data typesdata class LocationAndResponse(val location: Location, val response: Response)
Observable.combineLatest(location, webResponse){ a, b -> LocationAndResponse(a, b)}
.distinctUntilChanged()
.map { doSomething(it.location, it.response) }
![Page 19: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/19.jpg)
Rx & Null safety
![Page 20: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/20.jpg)
Rx & Null Safetyvar a: String = "abc"
a = null // compilation error
![Page 21: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/21.jpg)
Rx & Null Safetyvar a: String = "abc"
a = null // compilation error
var b: String? = "abc"
b = null // ok
![Page 22: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/22.jpg)
Rx & Null Safetyvar a: String = "abc"
a = null // compilation error
var b: String? = "abc"
b = null // ok
val l = b.length // error: variable 'b' can be null
![Page 23: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/23.jpg)
Rx & Null Safetyif (b != null && b.length > 0)
print("String of length ${b.length}")
else
print("Empty string")
![Page 24: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/24.jpg)
Rx & Null Safetyobservable //Observable<Int?>
.filter { it != null }
.subscribe { println(it) } //Observable<Int?>
![Page 25: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/25.jpg)
Rx & Null SafetylistOf(1, 2, 3, null) // Array<Int?>
.filter { it != null }
.forEach { println(it) } // Array<Int?>
![Page 26: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/26.jpg)
Rx & Null SafetylistOf(1, 2, 3, null) // Array<Int?>
.filterNotNull()
.forEach { println(it) } // Array<Int?>
![Page 27: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/27.jpg)
Rx & Null Safetyfun filterNotNull() {
}
![Page 28: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/28.jpg)
Rx & Null Safetyfun Observable.filterNotNull() {
}
![Page 29: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/29.jpg)
Rx & Null Safetyfun <T> Observable<T?>.filterNotNull(): Observable<T> {
}
![Page 30: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/30.jpg)
Rx & Null Safetyfun <T> Observable<T?>.filterNotNull(): Observable<T> {
}
![Page 31: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/31.jpg)
Rx & Null Safetyfun <T> Observable<T?>.filterNotNull(): Observable<T> {
return filter { it != null } as Observable<T>
}
![Page 32: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/32.jpg)
Rx & Null Safetyobservable //Observable<Int?>
.filterNotNull()
.subscribe { println(it) } //Observable<Int> PROFIT!!!
![Page 33: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/33.jpg)
Rx & Sealed classes
![Page 34: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/34.jpg)
Rx & Sealed classessealed class State {
class Progress() : State()
class Content(val data: Response) : State()
class Error(val error: Throwable) : State()
}
![Page 35: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/35.jpg)
Rx & Sealed classesstateObservable.subscribe {
when(it) {
is State.Progress -> { /* show progress */ }
is State.Content -> { it.data /* show content */ }
is State.Error -> { it.error /* show error */ }
}
}
![Page 36: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/36.jpg)
Rx & Sealed classesstateObservable
.filterByType(State.Content::class.java)
.subscribe { it.data }
![Page 37: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/37.jpg)
Rx & Sealed classesstateObservable
.filterByType(State.Content::class.java)
.subscribe { it.data }
![Page 38: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/38.jpg)
Rx & Sealed classesfun <T, R : T> Observable<T>.filterByType(type: Class<R>): Observable<R> =
filter { type.isInstance(it) } .map { type.cast(it) }
![Page 39: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/39.jpg)
Rx & Operator overloading
![Page 40: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/40.jpg)
Rx & Operator overloadingval subscription = CompositeSubscription()
subscription.add(observable1.subscribe { ... })
subscription.add(observable2.subscribe { ... })
subscription.add(observable3.subscribe { ... })
![Page 41: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/41.jpg)
Rx & Operator overloadingval subscription = CompositeSubscription()
subscription.add(observable1.subscribe { ... })
subscription.add(observable2.subscribe { ... })
subscription.add(observable3.subscribe { ... })
operator fun CompositeSubscription.plusAssign(subscription: Subscription) = add(subscription)
![Page 42: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/42.jpg)
Rx & Operator overloadingval subscription = CompositeSubscription()
subscription += observable1.subscribe { ... }
subscription += observable2.subscribe { ... }
subscription += observable3.subscribe { ... }
operator fun CompositeSubscription.plusAssign(subscription: Subscription) = add(subscription)
![Page 43: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/43.jpg)
Rx & Android Lifecycle
![Page 44: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/44.jpg)
Rx & Lifecycle
View Model
UI events
Data events
![Page 45: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/45.jpg)
RxBinding
![Page 46: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/46.jpg)
RxBindingJava
RxView.clicks(button)
![Page 47: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/47.jpg)
RxBindingJava
RxView.clicks(button)
Kotlin
button.clicks()
![Page 48: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/48.jpg)
RxBindingJava
RxView.clicks(button)
.subscribe(RxTextView.text(textView));
Kotlin
button.clicks()
![Page 49: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/49.jpg)
RxBindingKotlin
button.clicks()
.subscribe(textView.text())
Java
RxView.clicks(button)
.subscribe(RxTextView.text(textView));
![Page 50: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/50.jpg)
RxBinding
![Page 51: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/51.jpg)
RxLifecycle
![Page 52: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/52.jpg)
RxLifecycleJAVA
myObservable
.compose(RxLifecycle.bindActivity(lifecycle))
.subscribe();
![Page 53: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/53.jpg)
RxLifecycleKOTLIN
myObservable
.bindWithLifecycle(activity)
.subscribe {}
JAVA
myObservable
.compose(RxLifecycle.bindActivity(activity))
.subscribe();
![Page 54: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/54.jpg)
RxLifecycleKOTLIN
myObservable
.bindWithLifecycle(activity)
.subscribe {}
myObservable
.bindUntilEvent(activity,ActivityEvent.PAUSE)
.subscribe {}
JAVA
myObservable
.compose(RxLifecycle.bindActivity(activity))
.subscribe();
![Page 55: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/55.jpg)
Rx & Type safe builders
![Page 56: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/56.jpg)
Rx & Type safe builders model.dataStream()
.bindWithLifecycle(view)
.subscribe(dataHandleAction)
model.editIntent()
.bindWithLifecycle(view)
.subscribe(gotoEditAction)
model.mapData()
.bindWithLifecycle(view)
.subscribe(markersHandleAction)
![Page 57: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/57.jpg)
Rx & Type safe builders view.bindWithLifecycle {
model.dataStream() with dataHandleAction
model.editIntent() with gotoEditAction
model.mapData() with markersHandleAction
}
![Page 58: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/58.jpg)
Rx & Type safe buildersobservable.subscribe { /* on next here*/ }
![Page 59: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/59.jpg)
Rx & Type safe buildersobservable.subscribe { /* on next here*/ }
observable.subscribe ({ /* onNext */ }, { /* onError*/ })
![Page 60: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/60.jpg)
Rx & Type safe buildersobservable.subscribe { /* on next here*/ }
observable.subscribe ({ /* onNext */ }, { /* onError*/ })
observable.subscribe ({ /* onNext */ }, { /* onError*/ }, { /* onComplete*/ })
![Page 61: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/61.jpg)
Rx & Type safe buildersobservable.subscribeWith {
onNext { }
onError { }
}
![Page 62: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/62.jpg)
Testing Rx & Kotlin
![Page 63: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/63.jpg)
Testing Rx & Kotlinval finiteObservable = Observable.from(arrayOf("1", "2", "3"))
val subscriber = TestSubscriber<String>()
finiteObservable.subscribe(subscriber)
subscriber.awaitTerminalEvent()
subscriber.assertValues("1", "2", "3")
![Page 64: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/64.jpg)
Testing Rx & Kotlinval finiteObservable = Observable.from(arrayOf("1", "2", "3"))
fun <T> Observable<T>.assertValues(vararg values: T) {
val subscriber = TestSubscriber<T>()
this.subscribe(subscriber)
subscriber.awaitTerminalEvent()
subscriber.assertValues(*values)
}
![Page 65: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/65.jpg)
Testing Rx & Kotlinval finiteObservable = Observable.from(arrayOf("1", "2", "3"))
fun <T> Observable<T>.assertValues(vararg values: T) {
val subscriber = TestSubscriber<T>()
this.subscribe(subscriber)
subscriber.awaitTerminalEvent()
subscriber.assertValues(*values)
}
finiteObservable.assertValues("1", "2", "3")
![Page 66: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/66.jpg)
Testing Rx & Kotlinval finiteObservable = Observable.from(arrayOf("1", "2", "3"))
infix fun <T> Observable<T>.assertValues(values: Array<T>) {
val subscriber = TestSubscriber<T>()
this.subscribe(subscriber)
subscriber.awaitTerminalEvent()
subscriber.assertValues(*values)
}
finiteObservable assertValues arrayOf("1", "2", "3")
![Page 67: "Kotlin и rx в android" Дмитрий Воронин (Avito)](https://reader033.vdocuments.site/reader033/viewer/2022042515/587cdd5a1a28abff0b8b6069/html5/thumbnails/67.jpg)
Testing Rx & Kotlinval finiteObservable = Observable.from(arrayOf("1", "2", "3"))
infix fun <T> Observable<T>.shouldProduce(values: Array<T>) {
val subscriber = TestSubscriber<T>()
this.subscribe(subscriber)
subscriber.awaitTerminalEvent()
subscriber.assertValues(*values)
}
finiteObservable shouldProduce arrayOf("1", "2", "3")