Slide 1

Slide 1 text

@fernando_cejas http://www.fernandocejas.com The Mayans Lost Guide To RxJava on Android

Slide 2

Slide 2 text

@fernando_cejas Curious learner Meet... Android lover Software engineer Geek

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

#Reactive 1- of, relating to, or marked by reaction or reactance. 2- readily responsive to a stimulus.

Slide 5

Slide 5 text

RxJava is a Java VM implementation of Reactive X (Reactive Extensions): ˝ a library for composing asynchronous and event-based programs by using observable sequences. What is RxJava?

Slide 6

Slide 6 text

Why should we go reactive?

Slide 7

Slide 7 text

Multithreading is always complex˝ Concurrency˝ Java Futures are Expensive to Compose˝ Java Futures˝ Callbacks Have Their Own Problems˝ Callbacks˝ @benjchristensen from @netflix

Slide 8

Slide 8 text

public class FuturesA { public static void run() throws Exception { ExecutorService executor = new ThreadPoolExecutor(4, 4, 1, TimeUnit.MINUTES, new LinkedBlockingQueue()); Future f1 = executor.submit(new CallToRemoteServiceA()); Future f2 = executor.submit(new CallToRemoteServiceB()); System.out.println(f1.get() + " - " + f2.get()); } } https://gist.github.com/benjchristensen/4670979 #Java Futures

Slide 9

Slide 9 text

#Java Futures https://gist.github.com/benjchristensen/4671081 public static void run() throws Exception { ExecutorService executor = new ThreadPoolExecutor(4, 4, 1, TimeUnit.MINUTES, new LinkedBlockingQueue()); try { // get f3 with dependent result from f1 Future f1 = executor.submit(new CallToRemoteServiceA()); Future f3 = executor.submit(new CallToRemoteServiceC(f1.get())); /* The work below can not proceed until f1.get() completes even though there is no dependency */ // also get f4/f5 after dependency f2 completes Future f2 = executor.submit(new CallToRemoteServiceB()); Future f4 = executor.submit(new CallToRemoteServiceD(f2.get())); Future f5 = executor.submit(new CallToRemoteServiceE(f2.get())); System.out.println(f3.get() + " => " + (f4.get() * f5.get())); } finally { executor.shutdownNow(); } }

Slide 10

Slide 10 text

#Java Futures https://gist.github.com/benjchristensen/4671081 public static void run4() throws Exception { ExecutorService executor = new ThreadPoolExecutor(4, 4, 1, TimeUnit.MINUTES, new LinkedBlockingQueue()); try { List> futures = new ArrayList>(); // kick off several async tasks futures.add(executor.submit(new CallToRemoteServiceA())); futures.add(executor.submit(new CallToRemoteServiceB())); futures.add(executor.submit(new CallToRemoteServiceC("A"))); futures.add(executor.submit(new CallToRemoteServiceC("B"))); futures.add(executor.submit(new CallToRemoteServiceD(1))); futures.add(executor.submit(new CallToRemoteServiceE(2))); futures.add(executor.submit(new CallToRemoteServiceE(3))); // as each completes do further work for (Future> f : futures) { /* this blocks so even if other futures in the list complete earlier they will wait until this one is done */ doMoreWork(f.get()); } } finally { executor.shutdownNow(); } }

Slide 11

Slide 11 text

Multithreading is always complex˝ Concurrency˝ Java Futures are Expensive to Compose˝ Java Futures˝ Callbacks Have Their Own Problems˝ Callbacks˝ @benjchristensen from @netflix

Slide 12

Slide 12 text

#Callbacks https://gist.github.com/benjchristensen/4677544 ... // get f3 with dependent result from f1 executor.execute(new CallToRemoteServiceA(new Callback() { @Override public void call(String f1) { executor.execute(new CallToRemoteServiceC(new Callback() { @Override public void call(String f3) { // we have f1 and f3 now need to compose with others System.out.println("intermediate callback: " + f3 + " => " + ("f4 * f5")); // set to thread-safe variable accessible by external scope f3Value.set(f3); latch.countDown(); } }, f1)); } })); ...

Slide 13

Slide 13 text

Observables Subscribers Subscriptions Schedulers Operators #RxJava Guys:

Slide 14

Slide 14 text

Observables The Observable object is who does the job. Represents an object that sends notifications (Provider) to a Subscriptor (Observer).

Slide 15

Slide 15 text

Observables Add 2 missing semantics to the Observer pattern: #1: Emits a signal to the consumer when there is no more data available. #2: Emits a signal to the consumer when an error has occurred.

Slide 16

Slide 16 text

Observables

Slide 17

Slide 17 text

Observables

Slide 18

Slide 18 text

Subscribers Subscribers provides a mechanism for receiving push- based notifications from Observables, and permits manual unsubscribing from these Observables.

Slide 19

Slide 19 text

Subscribers Not an observer pattern: Observables often don't start emitting items until someone explicitly subscribes to them.

Slide 20

Slide 20 text

Subscribers Observables often don't start emitting items until someone explicitly subscribes to them.

Slide 21

Slide 21 text

Subscribers public class DefaultSubscriber extends rx.Subscriber { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(T t) { } }

Slide 22

Slide 22 text

Subscriptions Subscriptions represents the link between your Observable and your Subscriber. #1: Subscriptions #2: CompositeSubscriptions

Slide 23

Slide 23 text

#1: Schedulers.io() #2: Schedulers.computation() #3: Schedulers.from() Schedulers If you want to introduce multithreading into your cascade of Observable operators, you can do so by instructing those operators (or particular Observables) to operate on particular Schedulers.

Slide 24

Slide 24 text

Operators Operators can be used in between the source Observable and the ultimate Subscriber to manipulate emitted items. You can even write your own custom operators.

Slide 25

Slide 25 text

map() Transform the items emitted by an Observable by applying a function to each item.

Slide 26

Slide 26 text

flatMap() Transforms the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable (no order)

Slide 27

Slide 27 text

concatMap() Transforms the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable (keeps order)

Slide 28

Slide 28 text

flatMap() vs concatMap() http://fernandocejas.com/2015/01/11/rxjava-observable-tranformation-concatmap-vs-flatmap/

Slide 29

Slide 29 text

filter() Emits the same item it received, but only if it passes the boolean check (predicate).

Slide 30

Slide 30 text

take() Emit only the first n items emitted by an Observable

Slide 31

Slide 31 text

doOnNext() Allows us to add extra behavior each time an item is emitted.

Slide 32

Slide 32 text

onError() is called if an exception is thrown at any time. Error handling The operators do not have to handle the exception.

Slide 33

Slide 33 text

onErrorResumeNext() Instructs an Observable to emit a sequence of items if it encounters an error. onErrorReturn() Instructs an Observable to emit a particular item when it encounters an error. onExceptionResumeNext() Instructs an Observable to continue emitting items after it encounters an exception. retry() If a source Observable emits an error, resubscribe to it in the hopes that it will complete without error. retryWhen() If a source Observable emits an error, pass that error to another Observable to determine whether to resubscribe to the source. Error handling Operators

Slide 34

Slide 34 text

#1: Observable and Subscriber can do anything #2: The Observable and Subscriber are independent of the transformational steps in between them. #3: Operators let you do anything to the stream of data. Key ideas behind RxJava http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

Slide 35

Slide 35 text

#1: Learning curve #2: Too many anonymous classes generated (OutOfMemory?) #3: Verbosity (retrolambda to the rescue?) But there are some pitfalls…

Slide 36

Slide 36 text

#Example: Clean Architecture

Slide 37

Slide 37 text

#Example: Clean Architecture

Slide 38

Slide 38 text

@PerActivity public class UserListPresenter extends DefaultSubscriber> implements Presenter { private UserListView viewListView; private final UseCase getUserListUseCase; @Inject public UserListPresenter(@Named("userList") UseCase getUserListUserCase, UserModelDataMapper userModelDataMapper) { this.getUserListUseCase = getUserListUserCase; } @Override public void destroy() { this.getUserListUseCase.unsubscribe(); } private void getUserList() { this.getUserListUseCase.execute(this); } ... } #Example: Reactive Presenter

Slide 39

Slide 39 text

#Example: Reactive Presenter @PerActivity public class UserListPresenter extends DefaultSubscriber> implements Presenter { ... @Override public void onCompleted() { this.hideViewLoading(); } @Override public void onError(Throwable e) { this.hideViewLoading(); this.showErrorMessage(new DefaultErrorBundle((Exception) e)); this.showViewRetry(); } @Override public void onNext(List users) { this.showUsersCollectionInView(users); } }

Slide 40

Slide 40 text

#Example: Clean Architecture

Slide 41

Slide 41 text

#Example: UseCase public abstract class UseCase { private final ThreadExecutor threadExecutor; private final PostExecutionThread postExecutionThread; private Subscription subscription = Subscriptions.empty(); protected UseCase(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) { this.threadExecutor = threadExecutor; this.postExecutionThread = postExecutionThread; } protected abstract Observable buildUseCaseObservable(); public void execute(Subscriber UseCaseSubscriber) { this.subscription = this.buildUseCaseObservable() .subscribeOn(Schedulers.from(threadExecutor)) .observeOn(postExecutionThread.getScheduler()) .subscribe(UseCaseSubscriber); } public void unsubscribe() { if (!subscription.isUnsubscribed()) subscription.unsubscribe(); } }

Slide 42

Slide 42 text

#Example: Execution Thread /** * MainThread (UI Thread) implementation based on a * {@link rx.Scheduler} which will execute actions on * the Android UI thread */ @Singleton public class UIThread implements PostExecutionThread { @Inject public UIThread() {} @Override public Scheduler getScheduler() { return AndroidSchedulers.mainThread(); } }

Slide 43

Slide 43 text

#Example: UseCase /** * This class is an implementation of {@link UseCase} that represents a * use case for retrieving a collection of all {@link User}. */ public class GetUserListUseCase extends UseCase { private final UserRepository userRepository; @Inject public GetUserListUseCase(UserRepository userRepository, ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) { super(threadExecutor, postExecutionThread); this.userRepository = userRepository; } @Override public Observable buildUseCaseObservable() { return this.userRepository.getUsers(); } }

Slide 44

Slide 44 text

#Example: Clean Architecture

Slide 45

Slide 45 text

#Example: Operator and Action public class CloudUserDataStore implements UserDataStore { private final RestApi restApi; private final UserCache userCache; private final Action1 saveToCacheAction = new Action1() { @Override public void call(UserEntity userEntity) { if (userEntity != null) { CloudUserDataStore.this.userCache.put(userEntity); } } }; public CloudUserDataStore(RestApi restApi, UserCache userCache) { this.restApi = restApi; this.userCache = userCache; } @Override public Observable> getUserEntityList() { return this.restApi.getUserEntityList(); } @Override public Observable getUserEntityDetails(final int userId) { return this.restApi.getUserEntityById(userId).doOnNext(saveToCacheAction); } }

Slide 46

Slide 46 text

#Example: Data transformation @Singleton public class UserDataRepository implements UserRepository { private final UserDataStoreFactory userDataStoreFactory; private final UserEntityDataMapper userEntityDataMapper; private final Func1, List> userListEntityMapper = new Func1, List>() { @Override public List call(List userEntities) { return UserDataRepository.this.userEntityDataMapper.transform(userEntities); } }; private final Func1 userDetailsEntityMapper = new Func1() { @Override public User call(UserEntity userEntity) { return UserDataRepository.this.userEntityDataMapper.transform(userEntity); } }; @Override public Observable> getUsers() { final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore(); return userDataStore.getUserEntityList().map(userListEntityMapper); } }

Slide 47

Slide 47 text

#Example: Observable creation @Override public Observable> getUserEntityList() { return Observable.create(new Observable.OnSubscribe>() { @Override public void call(Subscriber super List> subscriber) { if (isThereInternetConnection()) { try { String responseUserEntities = getUserEntitiesFromApi(); subscriber.onNext(userEntityJsonMapper.transformUserEntityCollection( responseUserEntities)); subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(new NetworkConnectionException(e.getCause())); } } else { subscriber.onError(new NetworkConnectionException()); } } }); }

Slide 48

Slide 48 text

#1: Good starting point to switch to Rx Observables. #2: No need to deal with threading an synchronization. #3: Very simple to wrap an http connection in an Observable How do I start with RxJava? Rx at data level

Slide 49

Slide 49 text

#1: We can convert our events into Rx Observables How do I start with RxJava? Rx at view level Observable input = Observable.FromEventPattern(textView, "TextChanged") .Select(_ => textbox.Text) .Throttle(TimeSpan.FromSeconds(0.5)) .DistinctUntilChanged();

Slide 50

Slide 50 text

#1: You will return Rx Observables in domain layer. #2: Be careful with side effects (Rx Schedulers other than UI Thread) How do I start with RxJava? Rx at domain level

Slide 51

Slide 51 text

#1: By default, RxJava is synchronous. #2: onSubscribe() is executed separately for every new subscriber. #3: Subscriptions leak memory. Tips and Tricks #4: Read the official documentation

Slide 52

Slide 52 text

References Reactive Programming on Android With RxJava https://mttkay.github.io/blog/2013/08/25/functional-reactive-programming-on-android-with-rxjava/ Grokking RxJava http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/ Reactive Programming in the Netflix API with RxJava http://techblog.netflix.com/2013/02/rxjava-netflix-api.html Rx for .NET and RxJava for Android http://futurice.com/blog/tech-pick-of-the-week-rx-for-net-and-rxjava-for-android https://github.com/android10/Android-CleanArchitecture Official Documentation https://github.com/ReactiveX/RxJava/wiki https://github.com/android10/Android-ReactiveProgramming

Slide 53

Slide 53 text

? ˝ Source: US Census Bureau Questions

Slide 54

Slide 54 text

@fernando_cejas http://soundcloud.com/jobs Thanks!