In this little journey, we are gonna see what RxJava offers to us in terms of android development. We will also learn how we can apply it to real life mobile projects by showing different examples and use cases.
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?
Multithreading is always complex˝ Concurrency˝ Java Futures are Expensive to Compose˝ Java Futures˝ Callbacks Have Their Own Problems˝ Callbacks˝ @benjchristensen from @netflix
#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(); } }
#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(); } }
Multithreading is always complex˝ Concurrency˝ Java Futures are Expensive to Compose˝ Java Futures˝ Callbacks Have Their Own Problems˝ Callbacks˝ @benjchristensen from @netflix
#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)); } })); ...
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.
Subscribers Subscribers provides a mechanism for receiving push- based notifications from Observables, and permits manual unsubscribing from these Observables.
#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.
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.
concatMap() Transforms the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable (keeps order)
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
#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/
#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(); } }
#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(); } }
#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
#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();
#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
#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
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