Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intro to RxJava and Dagger for Android

Intro to RxJava and Dagger for Android

A brief introduction to RxJava and Dagger for Android developers.

Kshitij Chauhan

November 14, 2019
Tweet

More Decks by Kshitij Chauhan

Other Decks in Programming

Transcript

  1. Who am I? • Kshitij Chauhan • Third year, CS

    Undergrad at DTU • Been doing Android for some time • Have made a couple of cool apps and libraries • Really, really like Papri chaat
  2. This is not a beginner friendly talk. If you still

    write all your code in Activities, or have just discovered Async tasks, this talk is not for you.
  3. AsyncTask • It is a solution in the Android SDK

    to run tasks off the main thread. • Wrapper around Handler and Threads • Should only be used for short tasks
  4. AsyncTask Advantages • Natively available in the Android SDK Disadvantages

    • Very easy to leak memory if not used correctly • Not truly concurrent: A single background threads processes multiple AsyncTasks sequentially • Clumsy API • Cancellation must be handled manually • Error handling is difficult
  5. HandlerThread • Android specific threads • In combination with a

    Looper and a Handler, they can be used to process tasks sequentially • Associated Handler has a mailbox to which tasks (messages) can be sent • Messages are processed one by one by the Looper • Thread is kept alive even when the mailbox is empty • Must be explicitly stopped
  6. HandlerThread Advantages • Natively available in the Android SDK Disadvantages

    • Cancellation must be handled manually • Multiple Handler Threads are required for processing tasks concurrently • The more Handler Threads you create, the more of them you have to manage. • Work scheduling must be handled manually • Difficult to use given its primitive nature • Error handling is difficult
  7. java.util.concurrent • Java concurrency utilities: ExecutorService, CompletableFuture, Streams and more

    • Native to the Java language, not just specific to Android • Architected by great Language designers, unlike the people who made Android
  8. java.util.concurrent Advantages • Natively available in the Java programming language

    • Applicable outside the Android world as well • Easy to distribute and share work between thread pools Disadvantages • Cancellation must be handled manually • The most useful APIs are only available for >= API 24 • Error handling is difficult.
  9. Where RxJava differs from them is in its operators, functional

    nature, and the ability to easily switch between threads.
  10. What is RxJava? RxJava is a JVM implementation of Reactive

    Extensions: a library for composing asynchronous and event based programs by using observable sequences. Reactive Extensions has a variety of implementations in different languages. Besides RxJava, there's also RxJS, RxPy, RxSwift, and others.
  11. RxJava • RxJava models event streams. • Multiple operators can

    be applied on an event stream to transform it. • The transformed event stream can then be subscribed-to, to get notifications on each emission. • The manipulation and observation of streams can be done on different threads seamlessly.
  12. RxJava • Streams can be either cold or hot. ◦

    Cold streams: Do not begin execution unless there is at least one subscriber listening ◦ Hot streams: These streams are always running, no matter if someone is listening or not. • During the flow of a stream, any errors are propagated downstream and can be handled by the subscriber. • Cancellation is easy.
  13. What are Streams? • Streams are flows of data. •

    They can emit any number of items • Someone listening to a stream is notified whenever an item is emitted
  14. Types of Streams Hot Streams • Start emission as soon

    as they are created • Emit items even when no one is listening • Used to model sources of events which occur regardless of listeners, such as User Input events and Location Updates Cold Streams • Only begin execution when someone starts listening • Useful for modelling event sources which should not run if no one is listening, such as database query results
  15. Observables • Observables are the simplest streams in Rx •

    They are cold in nature, ie, they begin execution only when someone starts listening to them • Observables can be observed by observers. • Observers are notified whenever the Observable emits an event
  16. Observables are very useful. Turning an existing source of data

    into an Observable helps us use the power of RxJava. So let us learn how to create observables.
  17. Creating Observables There are a lot of in-built methods to

    help us create Observables out of any data source
  18. Now that we know how to create Observables, let us

    see how to visualize them in our minds
  19. Other Streams • Flowables: Cold streams with support for backpressure

    • Subjects: Hot streams • Single: Represents a stream of only one value, not strictly a stream • And many more.
  20. RxJava Operators • An operator is a method which takes

    in a stream, applies some method on the data in the stream, and returns a new one. • RxJava has a rich set of operators to cater to every need • Writing your own operators is difficult, but possible • Always look for existing operators thoroughly before writing your own
  21. Map() operator • Transforms the emissions of an Observable by

    applying a function to each item • Essentially converts an Observable of one type into an observable of another type • The items in the input observable are transformed to the output type by the mapping function
  22. FlatMap() operator • Transforms each emission of an Observable into

    a new Observable, then flatten the emissions from each new Observable into a single one. • Each input item is mapped to create an Observable. • Then the items of each of these mapped Observables are flattened into a single observable.
  23. Observable.fromIterable(twitterUsernames()) .flatMap(twHandle -> tweets(twHandle)) @ haroldadm i n @ gpeal

    @ jakewharton twHandle -> tweets(twHandle) ... ... ... ... ... ... ... ... ...
  24. @ haroldadm i n @ gpeal @ jakewharton Som e

    Tweet Som e Tweet Som e Tweet ... ... ... ... ... ... ... ... ... (Observable of Observables) (Flattened to a single Observable)
  25. FlatMap does not preserve the order of emissions. If the

    ordering is important, then ConcatMap should be used instead.
  26. Threading • RxJava uses the concept of Schedulers to manage

    threading • A Scheduler is like a pool of threads • There are different schedulers suited for different tasks • The types of Schedulers are: ◦ IO ◦ Computation ◦ Single-Threaded ◦ Trampoline
  27. Schedulers • Schedulers.io(): For input/output tasks • Schedulers.computation(): For CPU

    bound tasks • Schedulers.single(): For tasks requiring sequential execution • Schedulers.trampoline(): For tasks suited to work-stealing
  28. Switching threads • An Rx Stream has two places where

    a thread of execution can be chosen: subscribeOn(), and observeOn() • subscribeOn() controls the thread on which the source starts emitting • observeOn() controls the thread on which the subscriber receives the results. • subscribeOn() affects things upstream, while observeOn() affects things downstream
  29. Using Android’s Main Thread • Sometimes we might want to

    get results of a stream on the Android Main Thread • To do this, we need to add a dependency on the RxAndroid library • With the dependency added, the Android Main Thread can be used with RxJava in this manner:
  30. Switching threads is easy with RxJava. It is dramatically simpler

    than other async utilities presented earlier.
  31. The reason? Observables are cold streams. We have only applied

    operators to streams so far, but never actually subscribed to any of them.
  32. Observing Observables • An observable can be observed using an

    Observer • An observer contains various callback methods, but the most important ones are: onNext() and onError() • Whenever an observable emits a value, the onNext() method is called using the latest value • Whenever an error occurs, the onError() method is called and the stream is terminated
  33. Observing Streams • Since Observables/Flowables are cold streams, they do

    not actually do any work unless observed. • When the first observer starts observing, the stream starts flowing.
  34. This stream will keep on emitting until any of the

    following condition is met: • All values provided by twitterUsernames() have been emitted, or • An error occurs in the stream somewhere, or • We cancel the subscription early
  35. Managing subscriptions is important on Android. We must cancel our

    subscriptions when we don’t need them anymore, or else they will waste resources.
  36. Whenever we call subscribe() on an Observable, we get a

    Disposable in return. This Disposable can be used to cancel the subscription before the stream terminates.
  37. Providing an onError() method is equally important. If our stream

    encounters an error and does not have an onError() handler, our application will crash.
  38. Pure Functions • In functional programming, we prefer having pure

    functions. • Pure functions take in an input and provide an output. They don’t affect things outside their scope. • This means that pure functions can not modify the state of an application. • Therefore an application can’t just be composed of pure functions.
  39. Side Effects • To affect the state of an application,

    we use Side Effects • Unlike pure functions, they only exist to modify things outside their scope. • Side Effects and pure functions together make up an application
  40. RxJava and Functional Programming • RxJava streams are pure functions.

    • The entire state of the stream is contained inside it. • A stream does not affect the outside world, it just operates on its own data • RxJava has support for side-effects to affect things outside the stream
  41. RxJava and Functional Programming • Side Effects in RxJava are

    used like operators. • Unlike operators, they do not contribute to the stream: they affect the state outside it.
  42. What is Dagger? Dagger is a dependency injection library maintained

    by Google. Unlike its alternatives such as Guice, Dagger is fully static and works at compile time. It uses annotation processing to generate the dependency graph and factories at compile time.
  43. Dependency Injection • Dependency Injection is a technique in which

    an object’s dependencies are provided to it, rather than letting the object create them. • It has many benefits, including flexibility and easier testing. • Helps us write better code and create a better architecture.
  44. Dependency Injection • There are two kinds of injections: Constructor

    Injection, and Field injection. • We should always prefer Constructor injection where possible. • In places where we do not control the constructors (such as Android Activities/Fragments), we use field Injection.
  45. Because now we have made our Network Service more flexible.

    Suppose we have multiple implementations of our Cache.
  46. Dependency Injection If we create the Cache ourselves, we lose

    the flexibility to use multiple implementations easily
  47. Dependency Injection If someone else provides us with a Cache,

    we won’t need to limit ourselves anymore. They can provide any implementation they need.
  48. @Inject • To make Dagger aware of our classes, we

    need to annotate their constructors with @Inject • For each class with an @Inject constructor, Dagger adds it to our dependency graph. • If our class needs a dependency from this graph, Dagger can automatically provide it for us.
  49. Dagger can handle internal dependencies on its own, because we

    annotate their constructors with @Inject
  50. Dagger Modules • Dagger modules are used to inform Dagger

    about external dependencies our application will need. • Modules are classes/abstract classes/interfaces annotated with @Module • Modules contain static methods which create and return external dependencies • Each such method must be annotated with @Provides • For methods that only bind dependencies, we must use @Binds • Methods with @Binds can be abstract
  51. Using Modules, we can tell Dagger how to create and

    satisfy external dependencies in our app.
  52. We have been using Constructor Injection so far. Constructor Injection

    only works for classes whose constructors we can control. Therefore we can not use it with Activities/Fragments.
  53. Dagger Components • Dagger components are interfaces annotated with @Component

    which tell Dagger to build the object graph. • Components are the ones which actually satisfy dependencies in our application. • Components depend on Modules which provide external dependencies. • If we create a component named AppComponent, Dagger will generate its implementation with the name DaggerAppComponent.
  54. Dagger Components • Components contain inject methods for each class

    using field injection. • Components can also be used to fetch dependencies outside of a constructor. This makes Dagger also work as a Service Locator. • Components need to be initialized when our Application is created.
  55. Components need to be initialized before we can use them.

    Most commonly they are initialized when our Application starts.