Kotlin и Rx в Android
Rx & Single Abstract Method
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
Rx & Single Abstract Method
public interface Func1<T, R> extends Function {
R call(T t);
}
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
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
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map { s -> s.hashCode() }
.subscribe { i -> println(i) }
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map { string -> string.hashCode() }
.subscribe { hashCode -> println(hashCode) }
Rx & Single Abstract Method
Observable.just("Hello, world!")
.map { it.hashCode() }
.subscribe { println(it) }
Rx & High-Order functions
Rx & High-Order functions
fun yourFunc(one: String, two: Func0<Int>)
Rx & High-Order functions
fun yourFunc(one: String, two: () -> Int)
Rx & High-Order functions
fun yourFunc(one: String, two: () -> Int)
yourFunc("Hi") { 1 }
Rx & High-Order functions
Observable.combineLatest(one, two) { a, b -> a + b }
Observable.zip(one, two, three) { a, b, c -> a + b + c }
Rx & Data types
Rx & Data types
Observable.combineLatest(location, webResponse){ a, b -> Pair(a, b) }
.distinctUntilChanged()
.map { doSomething(it.first, it.second) }
Rx & Data types
Observable.combineLatest(location, webResponse){ a, b -> LocationAndResponse(a, b)}
.distinctUntilChanged()
.map { doSomething(it.location, it.response) }
Rx & Data types
data class LocationAndResponse(val location: Location, val response: Response)
Observable.combineLatest(location, webResponse){ a, b -> LocationAndResponse(a, b)}
.distinctUntilChanged()
.map { doSomething(it.location, it.response) }
Rx & Null safety
Rx & Null Safety
var a: String = "abc"
a = null // compilation error
Rx & Null Safety
var a: String = "abc"
a = null // compilation error
var b: String? = "abc"
b = null // ok
Rx & Null Safety
var a: String = "abc"
a = null // compilation error
var b: String? = "abc"
b = null // ok
val l = b.length // error: variable 'b' can be null
Rx & Null Safety
if (b != null && b.length > 0)
print("String of length ${b.length}")
else
print("Empty string")
Rx & Null Safety
observable //Observable<Int?>
.filter { it != null }
.subscribe { println(it) } //Observable<Int?>
Rx & Null Safety
listOf(1, 2, 3, null) // Array<Int?>
.filter { it != null }
.forEach { println(it) } // Array<Int?>
Rx & Null Safety
listOf(1, 2, 3, null) // Array<Int?>
.filterNotNull()
.forEach { println(it) } // Array<Int?>
Rx & Null Safety
fun filterNotNull() {
}
Rx & Null Safety
fun Observable.filterNotNull() {
}
Rx & Null Safety
fun <T> Observable<T?>.filterNotNull(): Observable<T> {
}
Rx & Null Safety
fun <T> Observable<T?>.filterNotNull(): Observable<T> {
}
Rx & Null Safety
fun <T> Observable<T?>.filterNotNull(): Observable<T> {
return filter { it != null } as Observable<T>
}
Rx & Null Safety
observable //Observable<Int?>
.filterNotNull()
.subscribe { println(it) } //Observable<Int> PROFIT!!!
Rx & Sealed classes
Rx & Sealed classes
sealed class State {
class Progress() : State()
class Content(val data: Response) : State()
class Error(val error: Throwable) : State()
}
Rx & Sealed classes
stateObservable.subscribe {
when(it) {
is State.Progress -> { /* show progress */ }
is State.Content -> { it.data /* show content */ }
is State.Error -> { it.error /* show error */ }
}
}
Rx & Sealed classes
stateObservable
.filterByType(State.Content::class.java)
.subscribe { it.data }
Rx & Sealed classes
stateObservable
.filterByType(State.Content::class.java)
.subscribe { it.data }
Rx & Sealed classes
fun <T, R : T> Observable<T>.filterByType(type: Class<R>): Observable<R> =
filter { type.isInstance(it) } .map { type.cast(it) }
Rx & Operator overloading
Rx & Operator overloading
val subscription = CompositeSubscription()
subscription.add(observable1.subscribe { ... })
subscription.add(observable2.subscribe { ... })
subscription.add(observable3.subscribe { ... })
Rx & Operator overloading
val subscription = CompositeSubscription()
subscription.add(observable1.subscribe { ... })
subscription.add(observable2.subscribe { ... })
subscription.add(observable3.subscribe { ... })
operator fun CompositeSubscription.plusAssign(subscription: Subscription) = add(subscription)
Rx & Operator overloading
val subscription = CompositeSubscription()
subscription += observable1.subscribe { ... }
subscription += observable2.subscribe { ... }
subscription += observable3.subscribe { ... }
operator fun CompositeSubscription.plusAssign(subscription: Subscription) = add(subscription)
Rx & Android Lifecycle
Rx & Lifecycle
View Model
UI events
Data events
RxBinding
RxBinding
Java
RxView.clicks(button)
RxBinding
Java
RxView.clicks(button)
Kotlin
button.clicks()
RxBinding
Java
RxView.clicks(button)
.subscribe(RxTextView.text(textView));
Kotlin
button.clicks()
RxBinding
Kotlin
button.clicks()
.subscribe(textView.text())
Java
RxView.clicks(button)
.subscribe(RxTextView.text(textView));
RxBinding
RxLifecycle
RxLifecycle
JAVA
myObservable
.compose(RxLifecycle.bindActivity(lifecycle))
.subscribe();
RxLifecycle
KOTLIN
myObservable
.bindWithLifecycle(activity)
.subscribe {}
JAVA
myObservable
.compose(RxLifecycle.bindActivity(activity))
.subscribe();
RxLifecycle
KOTLIN
myObservable
.bindWithLifecycle(activity)
.subscribe {}
myObservable
.bindUntilEvent(activity,ActivityEvent.PAUSE)
.subscribe {}
JAVA
myObservable
.compose(RxLifecycle.bindActivity(activity))
.subscribe();
Rx & Type safe builders
Rx & Type safe builders
model.dataStream()
.bindWithLifecycle(view)
.subscribe(dataHandleAction)
model.editIntent()
.bindWithLifecycle(view)
.subscribe(gotoEditAction)
model.mapData()
.bindWithLifecycle(view)
.subscribe(markersHandleAction)
Rx & Type safe builders
view.bindWithLifecycle {
model.dataStream() with dataHandleAction
model.editIntent() with gotoEditAction
model.mapData() with markersHandleAction
}
Rx & Type safe builders
observable.subscribe { /* on next here*/ }
Rx & Type safe builders
observable.subscribe { /* on next here*/ }
observable.subscribe ({ /* onNext */ }, { /* onError*/ })
Rx & Type safe builders
observable.subscribe { /* on next here*/ }
observable.subscribe ({ /* onNext */ }, { /* onError*/ })
observable.subscribe ({ /* onNext */ }, { /* onError*/ }, { /* onComplete*/ })
Rx & Type safe builders
observable.subscribeWith {
onNext { }
onError { }
}
Testing Rx & Kotlin
Testing Rx & Kotlin
val finiteObservable = Observable.from(arrayOf("1", "2", "3"))
val subscriber = TestSubscriber<String>()
finiteObservable.subscribe(subscriber)
subscriber.awaitTerminalEvent()
subscriber.assertValues("1", "2", "3")
Testing Rx & Kotlin
val 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)
}
Testing Rx & Kotlin
val 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")
Testing Rx & Kotlin
val 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")
Testing Rx & Kotlin
val 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")

"Kotlin и rx в android" Дмитрий Воронин (Avito)

  • 1.
    Kotlin и Rxв Android
  • 2.
    Rx & SingleAbstract Method
  • 3.
    Rx & SingleAbstract 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
  • 4.
    Rx & SingleAbstract Method public interface Func1<T, R> extends Function { R call(T t); }
  • 5.
    Rx & SingleAbstract 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
  • 6.
    Rx & SingleAbstract 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
  • 7.
    Rx & SingleAbstract Method Observable.just("Hello, world!") .map { s -> s.hashCode() } .subscribe { i -> println(i) }
  • 8.
    Rx & SingleAbstract Method Observable.just("Hello, world!") .map { string -> string.hashCode() } .subscribe { hashCode -> println(hashCode) }
  • 9.
    Rx & SingleAbstract Method Observable.just("Hello, world!") .map { it.hashCode() } .subscribe { println(it) }
  • 10.
    Rx & High-Orderfunctions
  • 11.
    Rx & High-Orderfunctions fun yourFunc(one: String, two: Func0<Int>)
  • 12.
    Rx & High-Orderfunctions fun yourFunc(one: String, two: () -> Int)
  • 13.
    Rx & High-Orderfunctions fun yourFunc(one: String, two: () -> Int) yourFunc("Hi") { 1 }
  • 14.
    Rx & High-Orderfunctions Observable.combineLatest(one, two) { a, b -> a + b } Observable.zip(one, two, three) { a, b, c -> a + b + c }
  • 15.
    Rx & Datatypes
  • 16.
    Rx & Datatypes Observable.combineLatest(location, webResponse){ a, b -> Pair(a, b) } .distinctUntilChanged() .map { doSomething(it.first, it.second) }
  • 17.
    Rx & Datatypes Observable.combineLatest(location, webResponse){ a, b -> LocationAndResponse(a, b)} .distinctUntilChanged() .map { doSomething(it.location, it.response) }
  • 18.
    Rx & Datatypes data class LocationAndResponse(val location: Location, val response: Response) Observable.combineLatest(location, webResponse){ a, b -> LocationAndResponse(a, b)} .distinctUntilChanged() .map { doSomething(it.location, it.response) }
  • 19.
    Rx & Nullsafety
  • 20.
    Rx & NullSafety var a: String = "abc" a = null // compilation error
  • 21.
    Rx & NullSafety var a: String = "abc" a = null // compilation error var b: String? = "abc" b = null // ok
  • 22.
    Rx & NullSafety var a: String = "abc" a = null // compilation error var b: String? = "abc" b = null // ok val l = b.length // error: variable 'b' can be null
  • 23.
    Rx & NullSafety if (b != null && b.length > 0) print("String of length ${b.length}") else print("Empty string")
  • 24.
    Rx & NullSafety observable //Observable<Int?> .filter { it != null } .subscribe { println(it) } //Observable<Int?>
  • 25.
    Rx & NullSafety listOf(1, 2, 3, null) // Array<Int?> .filter { it != null } .forEach { println(it) } // Array<Int?>
  • 26.
    Rx & NullSafety listOf(1, 2, 3, null) // Array<Int?> .filterNotNull() .forEach { println(it) } // Array<Int?>
  • 27.
    Rx & NullSafety fun filterNotNull() { }
  • 28.
    Rx & NullSafety fun Observable.filterNotNull() { }
  • 29.
    Rx & NullSafety fun <T> Observable<T?>.filterNotNull(): Observable<T> { }
  • 30.
    Rx & NullSafety fun <T> Observable<T?>.filterNotNull(): Observable<T> { }
  • 31.
    Rx & NullSafety fun <T> Observable<T?>.filterNotNull(): Observable<T> { return filter { it != null } as Observable<T> }
  • 32.
    Rx & NullSafety observable //Observable<Int?> .filterNotNull() .subscribe { println(it) } //Observable<Int> PROFIT!!!
  • 33.
    Rx & Sealedclasses
  • 34.
    Rx & Sealedclasses sealed class State { class Progress() : State() class Content(val data: Response) : State() class Error(val error: Throwable) : State() }
  • 35.
    Rx & Sealedclasses stateObservable.subscribe { when(it) { is State.Progress -> { /* show progress */ } is State.Content -> { it.data /* show content */ } is State.Error -> { it.error /* show error */ } } }
  • 36.
    Rx & Sealedclasses stateObservable .filterByType(State.Content::class.java) .subscribe { it.data }
  • 37.
    Rx & Sealedclasses stateObservable .filterByType(State.Content::class.java) .subscribe { it.data }
  • 38.
    Rx & Sealedclasses fun <T, R : T> Observable<T>.filterByType(type: Class<R>): Observable<R> = filter { type.isInstance(it) } .map { type.cast(it) }
  • 39.
    Rx & Operatoroverloading
  • 40.
    Rx & Operatoroverloading val subscription = CompositeSubscription() subscription.add(observable1.subscribe { ... }) subscription.add(observable2.subscribe { ... }) subscription.add(observable3.subscribe { ... })
  • 41.
    Rx & Operatoroverloading val subscription = CompositeSubscription() subscription.add(observable1.subscribe { ... }) subscription.add(observable2.subscribe { ... }) subscription.add(observable3.subscribe { ... }) operator fun CompositeSubscription.plusAssign(subscription: Subscription) = add(subscription)
  • 42.
    Rx & Operatoroverloading val subscription = CompositeSubscription() subscription += observable1.subscribe { ... } subscription += observable2.subscribe { ... } subscription += observable3.subscribe { ... } operator fun CompositeSubscription.plusAssign(subscription: Subscription) = add(subscription)
  • 43.
    Rx & AndroidLifecycle
  • 44.
    Rx & Lifecycle ViewModel UI events Data events
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
    Rx & Typesafe builders
  • 56.
    Rx & Typesafe builders model.dataStream() .bindWithLifecycle(view) .subscribe(dataHandleAction) model.editIntent() .bindWithLifecycle(view) .subscribe(gotoEditAction) model.mapData() .bindWithLifecycle(view) .subscribe(markersHandleAction)
  • 57.
    Rx & Typesafe builders view.bindWithLifecycle { model.dataStream() with dataHandleAction model.editIntent() with gotoEditAction model.mapData() with markersHandleAction }
  • 58.
    Rx & Typesafe builders observable.subscribe { /* on next here*/ }
  • 59.
    Rx & Typesafe builders observable.subscribe { /* on next here*/ } observable.subscribe ({ /* onNext */ }, { /* onError*/ })
  • 60.
    Rx & Typesafe builders observable.subscribe { /* on next here*/ } observable.subscribe ({ /* onNext */ }, { /* onError*/ }) observable.subscribe ({ /* onNext */ }, { /* onError*/ }, { /* onComplete*/ })
  • 61.
    Rx & Typesafe builders observable.subscribeWith { onNext { } onError { } }
  • 62.
  • 63.
    Testing Rx &Kotlin val finiteObservable = Observable.from(arrayOf("1", "2", "3")) val subscriber = TestSubscriber<String>() finiteObservable.subscribe(subscriber) subscriber.awaitTerminalEvent() subscriber.assertValues("1", "2", "3")
  • 64.
    Testing Rx &Kotlin val 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) }
  • 65.
    Testing Rx &Kotlin val 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")
  • 66.
    Testing Rx &Kotlin val 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")
  • 67.
    Testing Rx &Kotlin val 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")