Indice
1 Perché RxKotlin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1 Differenze e affinità con RxJava . . . . . . . . . . . . . . . . . . . . . . 3
2 Fasi preliminari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1 Importare RxKotlin 2 su Android Studio . . . . . . . . . . . . . . . . . . 4
3 Concetti di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.1 Entità osservabili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
- Tipologie e conversioni . . . . . . . . . . . . . . . . . . . . . . 6
- Creazione di observable . . . . . . . . . . . . . . . . . . . . . 8
- Metodi di creazione agili . . . . . . . . . . . . . . . . . . . . 12
- Cold observable . . . . . . . . . . . . . . . . . . . . . . . . . 14
- Hot observable . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2 Entità osservatrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
- Tipologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
- Creazione di observer . . . . . . . . . . . . . . . . . . . . . . 17
3.3 Subjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4 Caratteristiche avanzate . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.1 Schedulers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2 Multithreading con RxAndroid . . . . . . . . . . . . . . . . . . . . . 22
4.3 Backpressure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.4 Operatori per i flussi di dati . . . . . . . . . . . . . . . . . . . . . . 25
- Operatori di trasformazione . . . . . . . . . . . . . . . . . . . 26
- Operatori di filtraggio . . . . . . . . . . . . . . . . . . . . . . 29
- Operatori di combinazione . . . . . . . . . . . . . . . . . . . . 34
- Altri operatori di utilità . . . . . . . . . . . . . . . . . . . . . 36
5 Confronto con le coroutines . . . . . . . . . . . . . . . . . . . . . . . . . 38
6 Test del codice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1 INDICE INDICE Bibliografia 40 2
RxKotlin su Android
RxKotlin è una libreria che implementa i principali concetti della programmazione reattiva per il linguaggio Kotlin. È inoltre in buona parte influenzata dal paradigma di programmazione funzionale, fornendo difatti strumenti per la composizione in cascata degli operatori (funzioni) e per la rimozione degli effetti collaterali.
RxKotlin possiede quindi il modello produttore/consumatore (osservabile/osservatore) tipico del mondo reattivo, introducendo tuttavia anche funzioni per la composizione, trasformazione, filtraggio e manipolazione dei flussi di dati osservabili.
1 Perché RxKotlin
In questi appunti si è scelto di descrivere RxKotlin per diversi motivi: innanzitutto perché è un potente strumento in grado di fondere insieme sia le utili caratteristiche innovative del moderno linguaggio Kotlin, sia le idee e i concetti già discussi del paradigma di programmazione reattiva. Inoltre, lo si è scelto anche poiché Kotlin è un linguaggio di programmazione ufficialmente supportato per lo sviluppo di applicazioni Android; risulta dunque la scelta più naturale, dato che questi appunti descrivono l’approccio della Reactive Programming al mondo Android.
1.1 Differenze e affinità con RxJava
RxKotlin è una libreria che aggiunge utili funzioni ed estende nella pratica RxJava [2]. La prima può quindi essere vista come un ‘wrapper‘ scritto in Kotlin della seconda, integrando quindi tutte le funzionalità linguistiche e i miglioramenti sintattici che hanno reso famoso questo moderno linguaggio rispetto al predecessore.
In ultima analisi: RxKotlin si propone di ereditare e raccogliere tutte le caratteristiche di RxJava in una sola leggera libreria migliorata e di standardizzare le convenzioni per l’utilizzo di RxJava con Kotlin.
Le due librerie risultano equivalenti e interoperabili dal punto di vista delle funzionalità, sebbene RxKotlin risulti migliore per quanto riguarda la leggibilità del codice, la concisione e i servizi linguistici offerti al programmatore [3].
Esiste tuttora un supporto di RxKotlin per entrambe le versioni di RxJava (RxJava 1 e 2); nel prosieguo di questi appunti si descriverà RxKotlin 2, la versione attualmente più recente.
2 Fasi preliminari
Di seguito sono elencati i passi necessari per importare la libreria RxKotlin 2 in progetti gradle [4] sull’IDE Android Studio al fine di poter utilizzare le feature messe a disposizione.
2.1 Importare RxKotlin 2 su Android Studio
Ad oggi esiste una seconda versione di RxKotlin, per importarla su un progetto in Android Studio è sufficiente aggiungere le seguenti due linee nelle dependencies del file dell’applicazione: build.gradle
implementation ’io.reactivex.rxjava2:rxandroid:2.x.y’
implementation ’io.reactivex.rxjava2:rxkotlin:2.w.z’
dove x.y e w.z vanno sostituiti con i numeri delle versioni che si intendono importare; attualmente le ultime versioni sono, rispettivamente per RxAndroid e RxKotlin, la 2.1.0 e la 2.2.0.
È bene precisare che non è necessario importare RxAndroid per programmare in RxKotlin, tuttavia è nella pratica quasi un obbligo nel caso si programmi su smartphone, poiché la libreria (estensione reattiva per Android) fornisce diversi scheduler per eseguire codice su thread separati e sul Main Thread di Android. In questo modo si possono facilmente eseguire compiti su un thread in background per poi mostrare il risultato tramite interfaccia grafica (utilizzando l’UI Thread).
Questo consente per esempio di sostituire l’implementazione di un AsyncTask, risparmiando diverse linee di codice e rendendo il listato generalmente più chiaro e leggibile. 4 5
Successivamente è necessario (se non è già impostato) configurare Android Studio al fine di poter utilizzare le feature di Java 8; RxKotlin utilizza infatti un approccio di programmazione orientato al funzionale, dunque risulta utile (e consigliato) utilizzare alle volte lambda expression e method reference (introdotti dalla versione 8 di Java). Per assolvere al compito è sufficiente aggiungere due linee nel file build.gradle dell’app, come segue:
{android
1 // ...
2 {compileOptions
3 s o u r c e C o m p a t i b i l i t y J a v a V e r s i o n . VERSION 1 8
4 t a r g e t C o m p a t i b i l i t y J a v a V e r s i o n . VERSION 1 8
5 }
6 }
7
3 Concetti di base
All’interno di questa sezione verranno affrontati i concetti alla base del framework RxKotlin, soffermandosi principalmente sulla descrizione degli observable, degli observer e dei subject.
3.1 Entità osservabili
Come già accennato precedentemente, RxKotlin estende a livello logico il pattern Observer [1]. Questa caratteristica fornisce alla libreria due fondamentali classi di entità: quelle osservabili e quelle osservatrici. Le prime, chiamate spesso observable1, rappresentano sorgenti di dati o eventi e vengono reificate in oggetti di RxKotlin (presto verranno descritti uno per volta).
Di seguito verrà però presentata nell’ambito della programmazione in RxKotlin.
1 Così vengono chiamate le entità osservabili in RxKotlin 2, da non confondere con la classe Observable (da notare l’iniziale maiuscola e il diverso font), presente all’interno del framework. 5 6
Tipologie e conversioni
Di seguito vengono esposte le varie tipologie di entità osservabili presenti in RxKotlin 2, le loro caratteristiche di base e i metodi di conversione tra l’una e l’altra tipologia2. Ognuna di esse è rappresentata nella prossima tabella da una specifica classe della libreria.
| Tipologia | Descrizione |
|---|---|
| Flowable<T> | Emette 0 oppure n (numero qualsiasi) elementi e termina con un evento di successo o di errore. Supporta backpressure3, tecnica che permette di risolvere il problema che si presenta quando i dati/eventi vengono emessi ad una velocità superiore rispetto a quella di elaborazione da parte dell’osservatore. |
| Observable<T> | Emette 0 oppure n elementi e termina con un evento di successo o di errore. Non supporta backpressure. |
| Single<T> | Emette un singolo elemento oppure un evento di errore. Non supporta backpressure. |
| Maybe<T> | Emette 0 elementi, un singolo elemento oppure un evento di errore. Non supporta backpressure. |
| Completable | Non emette elementi, termina con un evento di successo o di errore. Non supporta backpressure. |
2 Attenzione: le tipologie di observable (quindi le classi) cambiano leggermente da RxKotlin a RxKotlin 2, in questi appunti viene descritta la più recente.
3 Argomento di cui si parlerà in maniera più approfondita successivamente. 6 7
Come si evince dalla precedente tabella, Flowable e Observable rappresentano stream di dati che possiedono lo stesso comportamento, l’unica differenza fra i due è che il primo supporta backpressure mentre il secondo ne è sprovvisto. Anche Single, Maybe e Completable sono sprovvisti di tecnica backpressure, si capirà più avanti che questo è ovvio (e necessario) poiché essi emettono al più un solo elemento.
Nelle prossime tabelle vengono invece esposti i nomi dei metodi da chiamare per convertire un oggetto da una data tipologia di observable ad un’altra. Da tener presente che a volte ci sono più metodi disponibili oppure che alcuni richiedono una certa logica per essere attuati correttamente:
| Da | A Flowable | Observable | Single |
|---|---|---|---|
| Flowable | toObservable | first, firstOrError, single, singleOrError, last, lastOrError4 | |
| Observable | toFlowable5 | first, firstOrError, single, singleOrError, last, lastOrError4 | |
| Single | toFlowable | toObservable | |
| Maybe | toFlowable | toObservable | toSingle6 |
| Completable | toFlowable | toObservable | toSingle |
4 La presenza di più metodi è dovuta al fatto che durante la conversione da una sorgente multivalore ad una monovalore bisogna decidere quale elemento considerare come risultato della conversione.
5 Convertire un Observable (privo di backpressure) in un Flowable necessita di prendere una decisione: cosa fare con il flusso della sorgente Observable. Ci sono diverse strategie disponibili (come per esempio il buffering, la perdita di elementi oppure il mantenimento dell’ultimo valore) utilizzabili tramite le costanti definite nella enum BackpressureStrategy oppure tramite gli operatori standard di Flowable come onBackpressureBuffer, onBackpressureDrop e onBackpressureLatest, i quali permettono anche una personalizzazione ulteriore del comportamento di backpressure. 7 8
| Da | A Maybe | Completable |
|---|---|---|
| Flowable | firstElement, singleElement, lastElement | ignoreElements |
| Observable | firstElement, singleElement, lastElement | ignoreElements |
| Single | toMaybe | toCompletable |
| Maybe | ignoreElement | |
| Completable | toMaybe |
Creazione di observable
In questa sottosezione viene spiegato come avviene la creazione di oggetti observable, ricordando che con il termine observable ci si riferisce in generale alle entità osservabili di RxKotlin 2 (e non ad una loro specifica tipologia). Si incomincia per semplicità dalla classe Observable, listato 1:
{ −> val o b s e r v a b l e : O b s e r v a b l e <Int> = O b s e r v a b l e . c r e a t e e
1 { f o r ( i in 0 . . 3 )
2 e . onNext ( i )
3 {try
4 Thread . s l e e p ( 1 0 0 0 )
5 } {catch ( exception : InterruptedException )
6 e . onError ( exception )
7 }
8 }
9 e . onComplete ( )
10
} 11
Listato 1: Creazione di un Observable in RxKotlin 2
Viene creato un oggetto Observable che emette (onNext() riga 3) quattro interi da 0 a 3, uno dopo l’altro ad intervalli di un secondo (Thread.sleep(1000) riga 5). Tipicamente gli oggetti observable non iniziano a trasmettere dati finché un’entità osservatrice non vi si sottoscrive. In questo esempio non avvengono sottoscrizioni, viene solamente creato un oggetto Observable e descritto il comportamento che attuerà una volta ricevuta una sottoscrizione da parte di un oggetto osservatore.
Per questi motivi lo snippet di codice non esegue ancora nessun compito, tuttavia è utile inizialmente per comprendere alcuni meccanismi di base. È particolarmente importante sottolineare anche che a riga 5 il metodo sleep() viene eseguito dal Main Thread, bloccando l’interfaccia dell’app Android per un secondo ad ogni iterazione del ciclo for, di certo non un’ottima scelta; presto verrà spiegato come risolvere il problema eseguendo i task long-running in un thread separato. Infine è bene precisare come questo sia solo un esempio di base e mostri volutamente tutto ciò che succede passo passo, sebbene generalmente non venga quasi mai utilizzato tanto codice per la creazione di un Observable in reali progetti con RxKotlin 2; in seguito verranno descritti semplici tecniche per diminuire drasticamente le linee di codice necessarie.
Come è possibile intuire nel precedente listato, un oggetto Observable (in generale ogni tipo di observable) è molto simile ad un oggetto che implementa l’interfaccia Iterable di Java: data una sequenza, la itera ed emette ciascun elemento in ordine. Ogni volta che un Observable emette un elemento, notifica le sue entità osservatrici
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
-
Kotlin - Appunti dettagliati con esempi di codice (42 pagine)
-
Event, Intent, Menu e I/O Android
-
Concetti fondamentali SO Android
-
Riassunti esame Sviluppo di mobile software