Reactive para Android
Elisa de Gregorio
¿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
Ok show me now!
Time
Observer Observable
Subscribe
On Next *
OnError |
OnComplete
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);
}
});
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”
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
Que Evita RXJava
Callbacks:
public class User{
String name;
String surname;
String fullName;
}
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;
}
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;
}
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;
}
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;
}
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() {
}
});
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;
}
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);
}
});
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;
}
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
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
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)
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);
}
});
Subscriptions con memory leaks!
Sin problemas potenciales
Observable.just(1).subscribe(... this.something());
Memory Leak!!
Observable.interval(1, TimeUnit.SECONDS).subscribe(... this.something());
Subscriptions con memory leaks!
Sin problemas potenciales
Observable.just(1).subscribe(... this.something());
Memory Leak!!
Observable.interval(1, TimeUnit.SECONDS).subscribe(... this.something());
Solución:
RXJava1: Unsubscribe() RXJava2: Dispose()
RXJava1:CompositeSubscription RXJava2:CompositeDisposable
Schedulers 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);
}
});
Indican en qué hilo deben
ejecutarse las operaciones
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);
}
});
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);
}
});
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);
}
});
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);
}
});
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);
}
});
Reactive operations
Reactive operations
http://reactivex.io/documentation/operators.html
● Crear Observables: Create, Defer, From, Interval, Just ...
● Transformar Observables: Buffer, FlatMap, Map, Scan ...
● Filtrar Observables: First, ElementAt, Distinct, Take …
● Combinar Observables: Join, CombineLatest, Zip…
● Errores: Catch, Retry
● Condicionales: All, Amb, Contains, DefaultIfEmpty…
● Matemáticos: Average, Concat, Count, Max, Reduce…
● BackPressure: Buffer, Sample, Window…
Crear Observables
RxJava tiene varios métodos para crear observables
● Observable.just("Hello")
● Observable.fromIterable()
● Observable.fromArray()
● Observable.fromCallable()
● Observable.fromFuture()
● Observable.interval()
Crear Observables
RxJava tiene varios métodos para crear observables
● Observable.just("Hello")
● Observable.fromIterable()
● Observable.fromArray()
● Observable.fromCallable()
● Observable.fromFuture()
● Observable.interval()
String adventure="Time";
Observable.just(adventure)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
Log : Time
String[] adventureTime={"what","time","is","it?"};
Observable.just(adventureTime)
.subscribe(new Subscriber<String[]>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(String[] s) {
Log.d("Test", s);
}
});
Log : Time [what,time, is,it]
Crear Observables
RxJava tiene varios métodos para crear observables
● Observable.just("Hello")
● Observable.fromArray()
● Observable.fromIterable()
● Observable.fromCallable()
● Observable.fromFuture()
● Observable.interval()
Log : Time what
time
is
it
String[] adventureTime={"what","time","is","it?"};
Observable.from(adventureTime)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
String adventure="Time";
Observable.just(adventure)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(String s) {
Log.d("Test", s);
}
});
FlatMap
http://reactivex.io/documentation/operators/flatmap.html
FlatMap- Map-Zip
http://reactivex.io/documentation/operators/map.html | http://rxmarbles.com/#map
FlatMap- Map-Zip
http://reactivex.io/documentation/operators/zip.html | http://rxmarbles.com/#zip
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);
}
});
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());
}
});
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());
}
});
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();
}
});
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);
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);
RXJava en la práctica
Data Domain View
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
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
Domain
RXJava en la práctica
Casos de uso
public Observable<Github> getGithubUser(String login){
return mGithubRepository.getUser(login);
}
Interactor
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);
}
});
RXTesting- Test Unitario- Dominio
@Before
public void setUp() throws Exception {
githubRepositoryMock = mock(GithubRepositoy.class);
mGetUserUseCase =new GetUserUseCaseImpl(githubRepositoryMock);
}
@Test
public void GetUserUseCase_Execute_GetGithubUser() throws Exception {
// Arrange
Github expectedGithub = new Github();
// Act
when(githubRepositoryMock.getUser("characterTest", 0)).thenReturn(Observable.just(expectedGithub));
Observable<Github> realGithubObj = mGetUserUseCase.execute("characterTest", 0);
TestSubscriber<Github> testSubscriber = new TestSubscriber<>();
realGithubObj.subscribe( testSubscriber);
// Assert
testSubscriber.assertNoErrors();
testSubscriber.assertValue(expectedGithub);
}
FIN!
Reactive para Android
Elisa de Gregorio

Iniciación rx java

  • 1.
  • 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
  • 4.
    Ok show menow! Time Observer Observable Subscribe On Next * OnError | OnComplete
  • 5.
    Ok show menow! 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 menow! 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 menow! 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
  • 8.
    Que Evita RXJava Callbacks: publicclass User{ String name; String surname; String fullName; }
  • 9.
    Que Evita RXJava Callbacks: publicvoid 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: publicclass 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 yretrolambda...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 observera 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 memoryleaks! Sin problemas potenciales Observable.just(1).subscribe(... this.something()); Memory Leak!! Observable.interval(1, TimeUnit.SECONDS).subscribe(... this.something());
  • 22.
    Subscriptions con memoryleaks! Sin problemas potenciales Observable.just(1).subscribe(... this.something()); Memory Leak!! Observable.interval(1, TimeUnit.SECONDS).subscribe(... this.something()); Solución: RXJava1: Unsubscribe() RXJava2: Dispose() RXJava1:CompositeSubscription RXJava2:CompositeDisposable
  • 23.
    Schedulers String adventure="Time"; Observable.just(adventure) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(newSubscriber<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); } }); Indican en qué hilo deben ejecutarse las operaciones
  • 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); } });
  • 29.
  • 30.
    Reactive operations http://reactivex.io/documentation/operators.html ● CrearObservables: Create, Defer, From, Interval, Just ... ● Transformar Observables: Buffer, FlatMap, Map, Scan ... ● Filtrar Observables: First, ElementAt, Distinct, Take … ● Combinar Observables: Join, CombineLatest, Zip… ● Errores: Catch, Retry ● Condicionales: All, Amb, Contains, DefaultIfEmpty… ● Matemáticos: Average, Concat, Count, Max, Reduce… ● BackPressure: Buffer, Sample, Window…
  • 31.
    Crear Observables RxJava tienevarios métodos para crear observables ● Observable.just("Hello") ● Observable.fromIterable() ● Observable.fromArray() ● Observable.fromCallable() ● Observable.fromFuture() ● Observable.interval()
  • 32.
    Crear Observables RxJava tienevarios métodos para crear observables ● Observable.just("Hello") ● Observable.fromIterable() ● Observable.fromArray() ● Observable.fromCallable() ● Observable.fromFuture() ● Observable.interval() String adventure="Time"; Observable.just(adventure) .subscribe(new Subscriber<String>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String s) { Log.d("Test", s); } }); Log : Time String[] adventureTime={"what","time","is","it?"}; Observable.just(adventureTime) .subscribe(new Subscriber<String[]>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String[] s) { Log.d("Test", s); } }); Log : Time [what,time, is,it]
  • 33.
    Crear Observables RxJava tienevarios métodos para crear observables ● Observable.just("Hello") ● Observable.fromArray() ● Observable.fromIterable() ● Observable.fromCallable() ● Observable.fromFuture() ● Observable.interval() Log : Time what time is it String[] adventureTime={"what","time","is","it?"}; Observable.from(adventureTime) .subscribe(new Subscriber<String>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String s) { Log.d("Test", s); } }); String adventure="Time"; Observable.just(adventure) .subscribe(new Subscriber<String>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String s) { Log.d("Test", s); } });
  • 34.
  • 35.
  • 36.
  • 37.
    Ejemplo Operaciones Lista deusuarios 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 deperfiles 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 deperfiles 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 deperfiles 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 usuariosde 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 usuariosde 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);
  • 43.
    RXJava en lapráctica Data Domain View
  • 44.
    Data RXJava en laprá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 laprá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 lapráctica Casos de uso public Observable<Github> getGithubUser(String login){ return mGithubRepository.getUser(login); } Interactor
  • 47.
    View RXJava en laprá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); } });
  • 48.
    RXTesting- Test Unitario-Dominio @Before public void setUp() throws Exception { githubRepositoryMock = mock(GithubRepositoy.class); mGetUserUseCase =new GetUserUseCaseImpl(githubRepositoryMock); } @Test public void GetUserUseCase_Execute_GetGithubUser() throws Exception { // Arrange Github expectedGithub = new Github(); // Act when(githubRepositoryMock.getUser("characterTest", 0)).thenReturn(Observable.just(expectedGithub)); Observable<Github> realGithubObj = mGetUserUseCase.execute("characterTest", 0); TestSubscriber<Github> testSubscriber = new TestSubscriber<>(); realGithubObj.subscribe( testSubscriber); // Assert testSubscriber.assertNoErrors(); testSubscriber.assertValue(expectedGithub); }
  • 49.
  • 50.