2. ¿Que es reactive?
- Se basa en que las apps son flujos de datos finitos o infinitos asíncronos.
- Nos abstrae
- Threading de bajo nivel
- Sincronización
- Estructuras de datos concurrentes
- Gestión de Errores *
- Nos permite concatenar transformaciones, componer datos de diferentes
fuentes de manera sencilla*
- Reactive- RXJava, RXJs, RX.NET, RXScala, RXPy …
- RXJava creado por Netflix
3.
4. Ok show me now!
Time
Observer Observable
Subscribe
On Next *
OnError |
OnComplete
5. Ok show me now!
String adventure="Time";
Observable.just(adventure)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
6. Ok show me now!
String adventure="Time";
Observable.just(adventure)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
Crear el Observable
“Flujo de datos”
7. Ok show me now!
String adventure="Time";
Observable.just(adventure)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
Te suscribes para
recoger los datos
LOG:
Time
Complete
9. Que Evita RXJava
Callbacks:
public void changeName(final User user,final String
name,final Callback<User> callback ){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
user.setName(name);
callback.onSuccess(user);
}
}, SERVICE_LATENCY_IN_MILLIS);
}
public class User{
String name;
String surname;
String fullName;
}
10. Que Evita RXJava
Callbacks: User user = new User();
userRepository.changeName(user,
"Name", new Callback<User>() {
@Override
public void onSuccess(User item) {
//:D
}
@Override
public void onError() {
//D:
}
});
public void changeName(final User user,final String
name,final Callback<User> callback ){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
user.setName(name);
callback.onSuccess(user);
}
}, SERVICE_LATENCY_IN_MILLIS);
}
public class User{
String name;
String surname;
String fullName;
}
11. Que Evita RXJava
Callbacks: userRepository.changeName(user, "Name", new Callback<User>() {
@Override
public void onSuccess(User item) {
userRepository.changeSurname(item, "Surname", new Callback<User>() {
@Override
public void onSuccess(User item) {
//:D
}
@Override
public void onError() { //D: }
});
}
@Override
public void onError() { //D: }
});
public class User{
String name;
String surname;
String fullName;
}
12. Que Evita RXJava
Callbacks: userRepository.changeName(user, "Name", new Callback<User>() {
@Override
public void onSuccess(User item) {
userRepository.changeSurname(item, "Surname", new Callback<User>() {
@Override
public void onSuccess(User item) {
userRepository.changeFullname(item, item.getName(), item.getSurmane(),
new Callback<User>() {
@Override
public void onSuccess(User item) {
//Finish!
}
@Override
public void onError() {//D:
}
});
}
@Override
public void onError() {//D:
}
});
}
@Override
public void onError() {
}
});
public class User{
String name;
String surname;
String fullName;
}
13. Que Evita RXJava
Callbacks:
public class User{
String name;
String surname;
String fullName;
}
CALLBACK HELL!
userRepository.changeName(user, "Name", new Callback<User>() {
@Override
public void onSuccess(User item) {
userRepository.changeSurname(item, "Surname", new Callback<User>() {
@Override
public void onSuccess(User item) {
userRepository.changeFullname(item, item.getName(), item.getSurmane(),
new Callback<User>() {
@Override
public void onSuccess(User item) {
//Finish!
}
@Override
public void onError() {//D:
}
});
}
@Override
public void onError() {//D:
}
});
}
@Override
public void onError() {
}
});
14. y en RXJava ...
Callbacks:
public Observable<User> changeName(final User user,final String name) {
return Observable.fromCallable(new Callable<User>() {
@Override
public User call() throws Exception {
user.setName(name);
return user;
}
});
}
public class User{
String name;
String surname;
String fullName;
}
15. y en RXJava ...
Callbacks:
public class User{
String name;
String surname;
String fullName;
}
Observable.just(new User())
.flatMap(new Func1<User, Observable<User>>() {
@Override
public Observable<User> call(User user) {
return userRepository.changeName(user, "name");
}
}).flatMap(new Func1<User, Observable<User>>() {
@Override
public Observable<User> call(User user) {
return userRepository.changeSurname(user, "surname");
}
}).flatMap(new Func1<User, Observable<User>>() {
@Override
public Observable<User> call(User user) {
return userRepository.changeFullName(user, user.getName(), user.getSurmane());
}
}).subscribe(new Subscriber<User>() {
@Override
public void onCompleted() {//Finish
}
@Override
public void onError(Throwable e) { //D:
}
@Override
public void onNext(User user) { // :D
log(user);
}
});
16. en RXJava y retrolambda...o Kotlin ! :D
Callbacks:
Observable.just(new User())
.flatMap(user -> userRepository.changeName(user, "name"))
.flatMap(user -> userRepository.changeSurname(user, "surname"))
.flatMap(user ->
userRepository.changeFullName(user, user.getName(), user.getSurmane()))
.subscribe(user ->log(user));
public class User{
String name;
String surname;
String fullName;
}
17. RXJava
● Se compone:
○ Set de clases para representar streams de datos - Observables
○ Set de clases para escuchar las fuentes de datos - Subscribers
○ Set de clases para modificar y componer los datos
TimeObserver/subscriber Observable
Subscribe
On Next *
OrError |
OnComplete
18. RxJava Observable types
● Observable<T>
○ Emite 0-n items, termina con error, o completo
● Flowable<T> -RXJava2
○ Emite 0-n items, termina con error, o completo
○ Soporta BackPressure
● Single<T>
○ Emite exactamente 1 item or error
● Maybe<T>
○ Emite 0 items o 1 item o error
● Completable
○ Emite 0 items, solo una señal de completado o error
19. Flowable vs Observable
BackPessure: poder controlar la velocidad con la que source emite datos
RXJava 1:
● Solo estaban los Observables (implementaban BackPressure)
● MissingBackpressureException D:
○ Hay formas de evitarlo https://github.com/ReactiveX/RxJava/wiki/Backpressure
RXJava 2:
● Flowables
● Observable (No backPressure) - Flowables (Con backPressure)
20. Subscriptions
Subscribe un observer a un
observable:
Subscription subscribe()
Subscription subscribe(Action1<? super T> onNext)
Subscription subscribe(Observer<? super T> observer)
Subscription subscribe(Subscriber<? super T> subscriber)
Subscription subscribe(Action1<? super T> onNext,
Action1<java.lang.Throwable> onError)
Subscription subscribe(Action1<? super T> onNext,
Action1<java.lang.Throwable> onError, Action0 onComplete)
String adventure="Time";
Observable.just(adventure)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
21. Subscriptions con memory leaks!
Sin problemas potenciales
Observable.just(1).subscribe(... this.something());
Memory Leak!!
Observable.interval(1, TimeUnit.SECONDS).subscribe(... this.something());
24. Schedulers
Indican en qué hilo deben
ejecutarse las operaciones:
● Scheduler.immediate()
Crea un Scheduler que ejecuta
inmediatamente el trabajo en el
hilo actual
String adventure="Time";
Observable.just(adventure)
.subscribeOn(Schedulers.inmediate())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
25. Schedulers
Indican en qué hilo deben
ejecutarse las operaciones:
● Scheduler.immediate()
● Scheduler.trampoline()
Crea un Scheduler que coloca
el trabajo, en la cola del hilo
actual.
String adventure="Time";
Observable.just(adventure)
.subscribeOn(Schedulers.trampoline())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
26. Schedulers
Indican en qué hilo deben
ejecutarse las operaciones:
● Scheduler.immediate()
● Scheduler.trampoline()
● Scheduler.newThread()
Crea un Scheduler que crea un
nuevo hilo para realizar el
trabajo.
String adventure="Time";
Observable.just(adventure)
.subscribeOn(Schedulers.newThead())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
27. Schedulers
Indican en qué hilo deben
ejecutarse las operaciones:
● Scheduler.immediate()
● Scheduler.trampoline()
● Scheduler.newThread()
● Scheduler.computation()
Crea un Scheduler para trabajo
computacional, tiene tantos
hilos como CPU tenga el
dispositivo.
String adventure="Time";
Observable.just(adventure)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
28. Schedulers
Indican en qué hilo deben
ejecutarse las operaciones:
● Scheduler.immediate()
● Scheduler.trampoline()
● Scheduler.newThread()
● Scheduler.computation()
● Scheduler.io()
Crea un Scheduler para
realizar llamadas I/O. Tiene un
thread-pool que crece a
demanda
String adventure="Time";
Observable.just(adventure)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.d("Test", "COMPLETE");
}
@Override
public void onError(Throwable e) {
Log.e("Test", "ERROR");
}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
37. Ejemplo Operaciones
Lista de usuarios de la charla
searchQuery(query)
.flatMap(new Func1<List<Users>, Observable<Users>>() {
@Override
public Observable<Users> call(List<Users> userList) {
return Observable.from(userList);
}
});
38. Ejemplo Operaciones
Lista de perfiles de usuarios de la charla
searchQuery(query)
.flatMap(new Func1<List<Users>, Observable<Users>>() {
@Override
public Observable<Users> call(List<Users> userList) {
return Observable.from(userList);
}
}).flatMap(new Func1<Users, Observable<LinkedINData>>() {
@Override
public Observable<LinkedINData> call(Users user) {
return linkedINQuery(user.getURL());
}
});
39. Ejemplo Operaciones
Lista de perfiles de usuarios de la charla
searchQuery(query)
.flatMap(new Func1<List<Users>, Observable<Users>>() {
@Override
public Observable<Users> call(List<Users> userList) {
return Observable.from(userList);
}
}).flatMap(new Func1<Users, Observable<LinkedINData>>() {
@Override
public Observable<LinkedINData> call(Users user) {
return linkedINQuery(user.getURL());
}
});
40. Ejemplo Operaciones
Lista de perfiles de usuarios de la charla que trabajan en Android
searchQuery(query)
.flatMap(new Func1<List<Users>, Observable<Users>>() {
@Override
public Observable<Users> call(List<Users> userList) {
return Observable.from(userList);
}
}).flatMap(new Func1<Users, Observable<LinkedINData>>() {
@Override
public Observable<LinkedINData> call(Users user) {
return linkedINQuery(user.getURL());
}).filter(new Func1<LinkedINData, Boolean>() {
@Override
public Boolean call(LinkedINData linkedINData) {
return linkedINData.worksInAndroid();
}
});
41. Ejemplo Operaciones
5 usuarios de la charla que trabajan en Android
searchQuery(query)
.flatMap(new Func1<List<Users>, Observable<Users>>() {
@Override
public Observable<Users> call(List<Users> userList) {
return Observable.from(userList);
}
}).flatMap(new Func1<Users, Observable<LinkedINData>>() {
@Override
public Observable<LinkedINData> call(Users user) {
return linkedINQuery(user.getURL());
}).filter(new Func1<LinkedINData, Boolean>() {
@Override
public Boolean call(LinkedINData linkedINData) {
return linkedINData.worksInAndroid();
}
}).take(5);
42. Ejemplo Operaciones
5 usuarios de la charla que trabajan en Android
searchQuery(query)
.flatMap(new Func1<List<Users>, Observable<Users>>() {
@Override
public Observable<Users> call(List<Users> userList) {
return Observable.from(userList);
}
}).flatMap(new Func1<Users, Observable<LinkedINData>>() {
@Override
public Observable<LinkedINData> call(Users user) {
return linkedINQuery(user.getURL());
}).filter(new Func1<LinkedINData, Boolean>() {
@Override
public Boolean call(LinkedINData linkedINData) {
return linkedINData.worksInAndroid();
}
}).take(5);
44. Data
RXJava en la práctica
Repositorio
BD/API/... public interface GithubService {
String SERVICE_ENDPOINT = "https://api.github.com";
@GET("/users/{login}")
Observable<GithubEntity> getUser(@Path("login") String login);
}
Datasources
Retrofit y Realm
45. Data
RXJava en la práctica
Repositorio
BD/API/...
public Observable<Github> getGithubUser(String login){
return dataStoreFactory.getUser(login)
//Map the Api object to the Domain object
.flatMap(new Function<GithubEntity, Observable<Github>>() {
@Override
public Observable<Github> apply
(@NonNull GithubEntity githubEntity) throws Exception {
return userResponseMapper.responseToModel(githubEntity);
}
});
}
Datasources
46. Domain
RXJava en la práctica
Casos de uso
public Observable<Github> getGithubUser(String login){
return mGithubRepository.getUser(login);
}
Interactor
47. View
RXJava en la práctica
Activity/fragment
Presenter
Model
mGetUserUseCase.execute(“user_login”)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Github>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError");
}
@Override
public void onNext(Github user) {
render(user);
}
});