Sviluppare app event-driven con RxJava su Android Rx
Sviluppare app event-driven con RxJava su Android
Rx
Boris D’AmatoAndroid Developer @
+BorisDAmato
@borisdamato
damatoboris
borisdamato
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Il Problema
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Il Problema
UI Thread
Main Thread
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
La Soluzione
RxJava RxJava è un’implementazione delle Reactive Extensions per la Java VM
Una libreria per realizzare programmi asincroni ed event-based utilizzando sequenze di
observable.
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Cosa significa “Reactive”?Un sistema Reattivo deve essere
ovvero
alle richieste degli utenti
a guasti ed errori
Responsivo Resiliente Elastico Orientato a messaggi
al carico di lavoro a eventi e messaggi
reagire
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Reactive Programming
Erik Meijer Ben Christensen
Rx.Net RxJava
Dávid Karnok
RxJava
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Reactive Programming
“Paradigma di programmazione basato su flussi di dati e propagazione dei cambiamenti” [Wikipedia]
Data flow Observer pattern Push vs Pull
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Gli Attori
Observable Observer Subscriber Subject
Generatore di dati
Reagisce alla ricezione dei dati
Ibrido tra Observable e
Observer
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Comunicazione Observable - Observer
Observer
subscribe
Observable
onNext()
onComplete()
onError()
onSubscribe()
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Android Time!
RecyclerView
Lista dei contatti
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Creazione di un Observableprivate Observable<String> getContacts() { return Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> e) throws Exception { List<String> contacts = new ArrayList<>();
Cursor cursor = [...];while (cursor.moveToNext()) {
String displayName = [...]; contacts.add(displayName);
}cursor.close();
for (String contact : contacts) { if (e.isDisposed()) return; e.onNext(contact); } if (!e.isDisposed()) e.onComplete();}});}
onError(Throwable e)
onNext(T item)
onComplete()
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Creazione di un Observable
List<Contact> contacts = [...];Observable.fromArray(contacts).subscribe([...]);
Observable.just()
.fromIterable().fromFuture()
.fromCallable()
.fromPublisher()
Observable.fromArray()
List<Contact> contacts = [...];Observable.just(contacts.get(0), contacts.get(1))
.subscribe([...]);
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Creazione di un Observable
Observable.empty() Observable.never() Observable.throw()
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Observer<Contact> observer = new Observer<Contact>() { @Override public void onSubscribe(Disposable d) { Log.d(TAG, "onSubscribe");
Log.d(TAG, "isDisposed: " + d.isDisposed()); }
@Override public void onNext(Contact item) { Log.d(TAG, "onNext"); adapter.addItem(item); }
@Override public void onError(Throwable e) { Log.e(TAG, "onError: " + e.getMessage); }
@Override public void onComplete() { Log.d(TAG, "onComplete"); }};
Subscribe
List<Contact> contacts = [...];Observable.fromArray(contacts)
.subscribe(observer);
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
Giorgio Carlo Andrea Gianni
Giorgio Gianni
getContacts().filter(new Predicate<Contact>() { @Override public boolean test(Contact contact) throws Exception { return contact.getName().startsWith("G"); }})
Filter
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering (Lambda Version)
Giorgio Carlo Andrea Gianni
Giorgio Gianni
getContacts().filter(contact -> contact.getName().startsWith("G"))Filter
https://github.com/evant/gradle-retrolambda
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
Giorgio Carlo Andrea Gianni
Giorgio
getContacts().take(3)Take
Carlo Andrea
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
Giorgio Carlo Andrea Gianni
getContacts().takeLast(3)TakeLast
Carlo Andrea Gianni
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
Giorgio Carlo Giorgio Gianni
getContacts().distinct()Distinct
Carlo GianniGiorgio
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
21
getTemperature().distinct()
21 20 19 20 21 22 23 23 21 22 21
21 20 19 22 23
Distinct
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
21
getTemperature().distinctUntilChanged()
21 20 19 20 21 22 23 23 21 22 21
DistinctUntil
Changed
21 20 19 20 21 22 23 21 22 21
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
21
getTemperature().sample(30, TimeUnit.SECONDS)
21 20 19 20 21 22 23 23 21 22 21
Sampleo
ThrottleLast
20 21
30 sec 30 sec
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Filtering
21
getTemperature().throttleFirst(30, TimeUnit.SECONDS)
21 20 19 20 21 22 23 23 21 22 21
ThrottleFirst
30 sec 30 sec
21 21 22
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Transforming
Giorgio Carlo Andrea Gianni
giorgio
getContacts().map((contact) -> {contact.setName(
contact.getName().toLowerCase());return contact;
})
Map
carlo andrea gianni
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Combining
Giorgio Carlo Andrea Gianni
Giorgio
Observable.merge(getContacts(), getImportingContacts())Merge
Carlo Andrea Gianni
Marco Francesco
Marco Francesco
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Combining
21° 22° 20° 18°
21° - 17:30
Zip
17:30 18:00 18:30 19:00
16°
22° - 18:00 20° - 18:30 18° - 19:00
Observable.zip(getTemperature(), getTime(), this::updateMonitor)
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Torniamo ad Android...private Observable<Contact> getContacts() { return Observable.create(new ObservableOnSubscribe<Contact>() { @Override public void subscribe(ObservableEmitter<String> e) throws Exception { List<String> contacts = new ArrayList<>();
SharedPreferences prefs = getActivity().getPreferences(Context.MOODE_PRIVATE);Type contactType = new TypeToken<List<Contact>>(){}.getType();String contactsGson = prefs.getString(“CONTACTS”, “”);
if (!contactsGson.isEmpty())contacts = new Gson().fromJson(contactsGson, contactType);
for (Contact contact : contacts) {e.onNext(contact);
} if (!e.isDisposed()) e.onComplete();}});}
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
… e accade questo...
D/StrictMode: StrictMode policy violation; ~duration=253 ms: android.os.StrictMode$ StrictModeDiskReadViolation: policy=31violation=2 at android.os.StrictMode $AndroidBlockGuardPolicy. onReadFromDisk(StrictMode.java:1135)
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
SoluzionegetContacts()
.subscribeOn( Schedulers.io() )
.subscribe([...]);
Schedulers.
computation()
io()
immediate()
newThread()
trampoline()
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
… altro problema
android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
getContacts().subscribeOn(Schedulers.io()).observeOn( AndroidSchedulers.mainThread() ).subscribe([...]);
Soluzione
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Nella pratica
● La ricerca debba essere eseguita ogni 500 millisecondi
Vogliamo che:
● La ricerca debba partire solo dopo che sia stati inseriti almeno 3 caratteri
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
RxBinding
compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'compile 'com.jakewharton.rxbinding:rxbinding-support-v4:0.4.0'compile 'com.jakewharton.rxbinding:rxbinding-design:0.4.0'
[ . . .]
https://github.com/JakeWharton/RxBinding
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Nella pratica
RxTextView.textChanges(searchField).debounce(500, TimeUnit.MILLISECONDS).filter( (charSequence) -> return charSequence.length() >= 3 ).subscribe( [...] )
Sviluppare App event-driven con RxJava su Android - Boris D’Amato
Grazie.
@borisdamato
+BorisDAmato