SlideShare ist ein Scribd-Unternehmen logo
1 von 32
Downloaden Sie, um offline zu lesen
ReactiveX
ReactiveX
• Problem: Verarbeiten von asynchronen Datensequenzen
• Mittel: Erweitertes Observer-Pattern mit Operatoren
Observer-Pattern
Subject
Observer A
Observer B
Observer C
subscribe
change
notify
Observable
Operatoren
Observable
• Drei Events statt einem
• onNext
• onCompleted
• onError
• Es gibt “Hot” und “Cold” Observables
• Variante: Single - für Sequenzen mit einem Element
Observable
Operatoren
onCompletedonNext
Quelle
Beobachter
Map
Filter
Operatoren
• Erzeugen, kombinieren, transformieren, filtern
• Ergebnis ist ein neues Observable
→ Operatoren können verkettet werden
• Reihenfolge ist entscheidend
Just
Observable
.just(1, 2, 3, 4, 5)

.subscribe(onNext = { print("$it ") })
Output: 1 2 3 4 5
Concat
Observable
.concat(Observable.just(1, 4, 5), Observable.just(2, 3))

.subscribe(onNext = { print("$it ") })
Output: 1 4 5 2 3
Filter
Observable
.just(1, 2, 3, 4, 5, 6)
.filter { it % 2 == 0 }

.subscribe(onNext = { print("$it ") })
Output: 2 4 6
Distinct
Observable
.just(1, 1, 2, 2, 3, 4, 5)
.distinct()

.subscribe(onNext = { print("$it ") })
Output: 1 2 3 4 5
Map
Observable
.just(1, 2, 3, 4, 5)
.map { it * 2 }

.subscribe(onNext = { print("$it ") })
Output: 2 4 6 8 10
FlatMap
Observable
.just(listOf(1, 2, 3), listOf(4, 5))
.flatMap { Observable.fromIterable(it) }

.subscribe(onNext = { print("$it ") })
Output: 1 2 3 4 5
ObserveOn & SubscribeOn
Observable
.fromCallable { longRunningOperation() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

.subscribe(onNext = { print("$it ") })
Beispiele
Preise für Topseller
fun getPrices(): Single<List<Price> {
val priceRequest = PriceRequest()

.setMaterial(material)

.setMaterialOption(materialOption)

.setFormats(topsellers.formats)



frameType?.let { priceRequest.setFrameType(it) }



return dataLayer

.getPrice(priceRequest)

.subscribeOn(Schedulers.io())

.toObservable()

.flatMap { Observable.fromIterable(it) }

.map { prices ->

Price(sumByFloat { it.priceCurrent }, sumByFloat { it.priceOriginal })

}

.toList()

.observeOn(AndroidSchedulers.mainThread())
}
App-API
@GET("price")
fun getPrice(
@QueryMap options: Map<String, String>,
@Query("formatTypes[]") formatTypes: List<String>
): Observable<ApiResponse<Prices>>
Texteingabe
hexInput
.textChanges()
.map { it.toString() }
.subscribe {
if (it.startsWith("#")) {
try {
color = Color.parseColor(it)
} catch (ignored: IllegalArgumentException) {}
} else {
hexInput.setText("#${hexInput.text}")
hexInput.setSelection(1)
}
}
Dropbox Bildersuche
private fun searchImages(): Observable<List<SearchMatch>> =

Observable

.merge(

(0 until ImagePickerHelpers.supportedExtensions.size).map {

searchImageType(ImagePickerHelpers.supportedExtensions[it])

}

)

.flatMap { Observable.fromIterable(it) }
.groupBy {
val path = it.metadata.pathDisplay
val directoryPath = path.substring(0, path.lastIndexOf("/"))
val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1)
directoryName
}
private fun searchImageType(extension: String): Observable<List<SearchMatch>> =

Observable.fromCallable {

dropboxClient

.files()

.search("", extension)

.matches

}
Dropbox Bildersuche
private fun searchImages(): Observable<List<SearchMatch>> =

Observable

.concatEager(

(0 until ImagePickerHelpers.supportedExtensions.size).map {

searchImageType(ImagePickerHelpers.supportedExtensions[it])

}

)

.flatMap { Observable.fromIterable(it) }
.groupBy {
val path = it.metadata.pathDisplay
val directoryPath = path.substring(0, path.lastIndexOf("/"))
val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1)
directoryName
}
.take(100)
private fun searchImageType(extension: String): Observable<List<SearchMatch>> =

Observable.fromCallable {

dropboxClient

.files()

.search("", extension)

.matches

}
Dropbox Bildersuche
private fun searchImages(): Observable<List<SearchMatch>> =

Observable

.concatEager(

(0 until ImagePickerHelpers.supportedExtensions.size).map {

searchImageType(ImagePickerHelpers.supportedExtensions[it])

}

)

.flatMap { Observable.fromIterable(it) }
.distinct { it.metadata.name }
.groupBy {
val path = it.metadata.pathDisplay
val directoryPath = path.substring(0, path.lastIndexOf("/"))
val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1)
directoryName
}
private fun searchImageType(extension: String): Observable<List<SearchMatch>> =

Observable.fromCallable {

dropboxClient

.files()

.search("", extension)

.matches

}
Dropbox Bildersuche
private fun searchImages(): Observable<List<SearchMatch>> =

Observable

.concatEager(

(0 until ImagePickerHelpers.supportedExtensions.size).map {

searchImageType(ImagePickerHelpers.supportedExtensions[it])

}

)

.flatMap { Observable.fromIterable(it) }
.filter { it.metadata.name.contains("myposter") }
.groupBy {
val path = it.metadata.pathDisplay
val directoryPath = path.substring(0, path.lastIndexOf("/"))
val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1)
directoryName
}
private fun searchImageType(extension: String): Observable<List<SearchMatch>> =

Observable.fromCallable {

dropboxClient

.files()

.search("", extension)

.matches

}
data class CollageModel(
val layouts: ImmutableList<CollageLayout>,
val selectedLayout: CollageLayout,
val selectedFormatGroup: CollageFormatGroup,
val tiles: ImmutableList<CollageTile>,
val texts: ImmutableList<CollageText>,
val rotations: Int,
val outerMargin: Float,
val innerMargin: Float,
val backgroundColor: Int,
⋮
)
MVP + ReactiveX
• Model-View-Presenter Pattern
• Model: Repräsentation des Zustands
• View: Darstellung des Zustands
• Presenter: Zustand verändern und View updaten
Subjects
• Sind Observer und Observable
• Geben einen Teil der ursprünglichen Daten weiter
• Varianten: Async, Behavior, Publish, Replay
BehaviorSubject
MVP + ReactiveX
• Presenter hat ein BehaviorSubject für Model-Objekte
• Bei Eingaben wird ein neues Model-Objekt erzeugt und das
onNext-Event des Subjects ausgelöst
• View beobachtet das Subject und updated das UI bei
onNext-Events
reactivex.io

Weitere ähnliche Inhalte

Was ist angesagt?

Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Loïc Knuchel
 
Collection pipeline par Mathieu Godart
Collection pipeline par  Mathieu GodartCollection pipeline par  Mathieu Godart
Collection pipeline par Mathieu GodartCocoaHeads France
 
Strutture dati 08-reshape
Strutture dati 08-reshapeStrutture dati 08-reshape
Strutture dati 08-reshapeStudiabo
 
Java & le pattern matching
Java & le pattern matchingJava & le pattern matching
Java & le pattern matchingDidier Plaindoux
 
RxSwift 예제로 감잡기
RxSwift 예제로 감잡기RxSwift 예제로 감잡기
RxSwift 예제로 감잡기Yongha Yoo
 

Was ist angesagt? (8)

Grouping object1
Grouping object1Grouping object1
Grouping object1
 
Program
ProgramProgram
Program
 
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
 
Collection pipeline par Mathieu Godart
Collection pipeline par  Mathieu GodartCollection pipeline par  Mathieu Godart
Collection pipeline par Mathieu Godart
 
Strutture dati 08-reshape
Strutture dati 08-reshapeStrutture dati 08-reshape
Strutture dati 08-reshape
 
Java & le pattern matching
Java & le pattern matchingJava & le pattern matching
Java & le pattern matching
 
RxSwift 예제로 감잡기
RxSwift 예제로 감잡기RxSwift 예제로 감잡기
RxSwift 예제로 감잡기
 
Macro
MacroMacro
Macro
 

Mehr von myposter GmbH

Concepts of Clean Code adapted for JavaScript - Tech'n'Drinks @myposter
Concepts of Clean Code adapted for JavaScript - Tech'n'Drinks @myposterConcepts of Clean Code adapted for JavaScript - Tech'n'Drinks @myposter
Concepts of Clean Code adapted for JavaScript - Tech'n'Drinks @mypostermyposter GmbH
 
Clean(er) Code - Tech'n'Drinks @myposter
Clean(er) Code - Tech'n'Drinks @myposterClean(er) Code - Tech'n'Drinks @myposter
Clean(er) Code - Tech'n'Drinks @mypostermyposter GmbH
 
Vue - State Transitions
Vue - State TransitionsVue - State Transitions
Vue - State Transitionsmyposter GmbH
 
Vue - Composing Components
Vue - Composing ComponentsVue - Composing Components
Vue - Composing Componentsmyposter GmbH
 
Vue - the Progressive Framework
Vue  - the Progressive FrameworkVue  - the Progressive Framework
Vue - the Progressive Frameworkmyposter GmbH
 
Microservices - Do one thing well
Microservices - Do one thing wellMicroservices - Do one thing well
Microservices - Do one thing wellmyposter GmbH
 
Optimising Image Loading
Optimising Image LoadingOptimising Image Loading
Optimising Image Loadingmyposter GmbH
 
Warum Affen die besseren Softwaretester sind
Warum Affen die besseren Softwaretester sindWarum Affen die besseren Softwaretester sind
Warum Affen die besseren Softwaretester sindmyposter GmbH
 

Mehr von myposter GmbH (10)

Concepts of Clean Code adapted for JavaScript - Tech'n'Drinks @myposter
Concepts of Clean Code adapted for JavaScript - Tech'n'Drinks @myposterConcepts of Clean Code adapted for JavaScript - Tech'n'Drinks @myposter
Concepts of Clean Code adapted for JavaScript - Tech'n'Drinks @myposter
 
Clean(er) Code - Tech'n'Drinks @myposter
Clean(er) Code - Tech'n'Drinks @myposterClean(er) Code - Tech'n'Drinks @myposter
Clean(er) Code - Tech'n'Drinks @myposter
 
ReRxSwift
ReRxSwiftReRxSwift
ReRxSwift
 
Vue - State Transitions
Vue - State TransitionsVue - State Transitions
Vue - State Transitions
 
Vue - Composing Components
Vue - Composing ComponentsVue - Composing Components
Vue - Composing Components
 
Vue - the Progressive Framework
Vue  - the Progressive FrameworkVue  - the Progressive Framework
Vue - the Progressive Framework
 
Microservices - Do one thing well
Microservices - Do one thing wellMicroservices - Do one thing well
Microservices - Do one thing well
 
Optimising Image Loading
Optimising Image LoadingOptimising Image Loading
Optimising Image Loading
 
Warum Affen die besseren Softwaretester sind
Warum Affen die besseren Softwaretester sindWarum Affen die besseren Softwaretester sind
Warum Affen die besseren Softwaretester sind
 
How Browsers Work
How Browsers Work How Browsers Work
How Browsers Work
 

Reactive x

  • 2. ReactiveX • Problem: Verarbeiten von asynchronen Datensequenzen • Mittel: Erweitertes Observer-Pattern mit Operatoren
  • 5. Observable • Drei Events statt einem • onNext • onCompleted • onError • Es gibt “Hot” und “Cold” Observables • Variante: Single - für Sequenzen mit einem Element
  • 8. Operatoren • Erzeugen, kombinieren, transformieren, filtern • Ergebnis ist ein neues Observable → Operatoren können verkettet werden • Reihenfolge ist entscheidend
  • 9.
  • 10. Just Observable .just(1, 2, 3, 4, 5)
 .subscribe(onNext = { print("$it ") }) Output: 1 2 3 4 5
  • 11.
  • 12. Concat Observable .concat(Observable.just(1, 4, 5), Observable.just(2, 3))
 .subscribe(onNext = { print("$it ") }) Output: 1 4 5 2 3
  • 13.
  • 14. Filter Observable .just(1, 2, 3, 4, 5, 6) .filter { it % 2 == 0 }
 .subscribe(onNext = { print("$it ") }) Output: 2 4 6
  • 15. Distinct Observable .just(1, 1, 2, 2, 3, 4, 5) .distinct()
 .subscribe(onNext = { print("$it ") }) Output: 1 2 3 4 5
  • 16. Map Observable .just(1, 2, 3, 4, 5) .map { it * 2 }
 .subscribe(onNext = { print("$it ") }) Output: 2 4 6 8 10
  • 17. FlatMap Observable .just(listOf(1, 2, 3), listOf(4, 5)) .flatMap { Observable.fromIterable(it) }
 .subscribe(onNext = { print("$it ") }) Output: 1 2 3 4 5
  • 18. ObserveOn & SubscribeOn Observable .fromCallable { longRunningOperation() } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())
 .subscribe(onNext = { print("$it ") })
  • 20. Preise für Topseller fun getPrices(): Single<List<Price> { val priceRequest = PriceRequest()
 .setMaterial(material)
 .setMaterialOption(materialOption)
 .setFormats(topsellers.formats)
 
 frameType?.let { priceRequest.setFrameType(it) }
 
 return dataLayer
 .getPrice(priceRequest)
 .subscribeOn(Schedulers.io())
 .toObservable()
 .flatMap { Observable.fromIterable(it) }
 .map { prices ->
 Price(sumByFloat { it.priceCurrent }, sumByFloat { it.priceOriginal })
 }
 .toList()
 .observeOn(AndroidSchedulers.mainThread()) }
  • 21. App-API @GET("price") fun getPrice( @QueryMap options: Map<String, String>, @Query("formatTypes[]") formatTypes: List<String> ): Observable<ApiResponse<Prices>>
  • 22. Texteingabe hexInput .textChanges() .map { it.toString() } .subscribe { if (it.startsWith("#")) { try { color = Color.parseColor(it) } catch (ignored: IllegalArgumentException) {} } else { hexInput.setText("#${hexInput.text}") hexInput.setSelection(1) } }
  • 23. Dropbox Bildersuche private fun searchImages(): Observable<List<SearchMatch>> =
 Observable
 .merge(
 (0 until ImagePickerHelpers.supportedExtensions.size).map {
 searchImageType(ImagePickerHelpers.supportedExtensions[it])
 }
 )
 .flatMap { Observable.fromIterable(it) } .groupBy { val path = it.metadata.pathDisplay val directoryPath = path.substring(0, path.lastIndexOf("/")) val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1) directoryName } private fun searchImageType(extension: String): Observable<List<SearchMatch>> =
 Observable.fromCallable {
 dropboxClient
 .files()
 .search("", extension)
 .matches
 }
  • 24. Dropbox Bildersuche private fun searchImages(): Observable<List<SearchMatch>> =
 Observable
 .concatEager(
 (0 until ImagePickerHelpers.supportedExtensions.size).map {
 searchImageType(ImagePickerHelpers.supportedExtensions[it])
 }
 )
 .flatMap { Observable.fromIterable(it) } .groupBy { val path = it.metadata.pathDisplay val directoryPath = path.substring(0, path.lastIndexOf("/")) val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1) directoryName } .take(100) private fun searchImageType(extension: String): Observable<List<SearchMatch>> =
 Observable.fromCallable {
 dropboxClient
 .files()
 .search("", extension)
 .matches
 }
  • 25. Dropbox Bildersuche private fun searchImages(): Observable<List<SearchMatch>> =
 Observable
 .concatEager(
 (0 until ImagePickerHelpers.supportedExtensions.size).map {
 searchImageType(ImagePickerHelpers.supportedExtensions[it])
 }
 )
 .flatMap { Observable.fromIterable(it) } .distinct { it.metadata.name } .groupBy { val path = it.metadata.pathDisplay val directoryPath = path.substring(0, path.lastIndexOf("/")) val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1) directoryName } private fun searchImageType(extension: String): Observable<List<SearchMatch>> =
 Observable.fromCallable {
 dropboxClient
 .files()
 .search("", extension)
 .matches
 }
  • 26. Dropbox Bildersuche private fun searchImages(): Observable<List<SearchMatch>> =
 Observable
 .concatEager(
 (0 until ImagePickerHelpers.supportedExtensions.size).map {
 searchImageType(ImagePickerHelpers.supportedExtensions[it])
 }
 )
 .flatMap { Observable.fromIterable(it) } .filter { it.metadata.name.contains("myposter") } .groupBy { val path = it.metadata.pathDisplay val directoryPath = path.substring(0, path.lastIndexOf("/")) val directoryName = directoryPath.substring(directoryPath.lastIndexOf("/") + 1) directoryName } private fun searchImageType(extension: String): Observable<List<SearchMatch>> =
 Observable.fromCallable {
 dropboxClient
 .files()
 .search("", extension)
 .matches
 }
  • 27. data class CollageModel( val layouts: ImmutableList<CollageLayout>, val selectedLayout: CollageLayout, val selectedFormatGroup: CollageFormatGroup, val tiles: ImmutableList<CollageTile>, val texts: ImmutableList<CollageText>, val rotations: Int, val outerMargin: Float, val innerMargin: Float, val backgroundColor: Int, ⋮ )
  • 28. MVP + ReactiveX • Model-View-Presenter Pattern • Model: Repräsentation des Zustands • View: Darstellung des Zustands • Presenter: Zustand verändern und View updaten
  • 29. Subjects • Sind Observer und Observable • Geben einen Teil der ursprünglichen Daten weiter • Varianten: Async, Behavior, Publish, Replay
  • 31. MVP + ReactiveX • Presenter hat ein BehaviorSubject für Model-Objekte • Bei Eingaben wird ein neues Model-Objekt erzeugt und das onNext-Event des Subjects ausgelöst • View beobachtet das Subject und updated das UI bei onNext-Events