Slide 1

Slide 1 text

RxJava and Dagger Advanced Android @haroldadmin @haroldadmin Kshitij Chauhan kshitijchauhan.me

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Some of my work

Slide 4

Slide 4 text

MoonShot A SpaceX companion app github.com/haroldadmin/MoonShot

Slide 5

Slide 5 text

MVI Arch library for Android built on Kotlin Coroutines github.com/haroldadmin/Vector

Slide 6

Slide 6 text

...and a lot of other cool libraries and apps github.com/haroldadmin

Slide 7

Slide 7 text

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.

Slide 8

Slide 8 text

Let’s get started.

Slide 9

Slide 9 text

The Asynchronous Toolkit A look at existing Async utilities available on Android

Slide 10

Slide 10 text

AsyncTask (Soon to be deprecated)

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

AsyncTask

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

HandlerThread Android specific threads

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

HandlerThread

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

java.util.concurrent Java Concurrency Utilities

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Java Concurrency Utilities

Slide 21

Slide 21 text

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.

Slide 22

Slide 22 text

All the existing utilities are available natively on Android. There are pros and cons to each.

Slide 23

Slide 23 text

Where RxJava differs from them is in its operators, functional nature, and the ability to easily switch between threads.

Slide 24

Slide 24 text

RxJava Functional Reactive Programming in Java

Slide 25

Slide 25 text

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.

Slide 26

Slide 26 text

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.

Slide 27

Slide 27 text

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.

Slide 28

Slide 28 text

Streams Flows of data

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Observables Simplest cold streams in Rx

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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.

Slide 34

Slide 34 text

Creating Observables Using built-in methods

Slide 35

Slide 35 text

Creating Observables Using built-in methods

Slide 36

Slide 36 text

Creating Observables Manually (not recommended)

Slide 37

Slide 37 text

Creating Observables There are a lot of in-built methods to help us create Observables out of any data source

Slide 38

Slide 38 text

Now that we know how to create Observables, let us see how to visualize them in our minds

Slide 39

Slide 39 text

Visualizing Observables

Slide 40

Slide 40 text

Visualizing Observables 1 second 1 second 1 second 1 second 1 second 1 second 1 second 1 second

Slide 41

Slide 41 text

They are streams of whatever data our source provides

Slide 42

Slide 42 text

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.

Slide 43

Slide 43 text

Now that we know Observables, let us see how we can modify their emissions

Slide 44

Slide 44 text

Operators Modifying data in streams

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Map() Observable -> mapFx -> Observable

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Map() Observable of numbers to Observable of number * 10

Slide 49

Slide 49 text

Observable.fromArray(1, 2, 3) .map(number -> number * 10)

Slide 50

Slide 50 text

FlatMap() Map one Observable to multiple Observables and flatten to a single Observable

Slide 51

Slide 51 text

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.

Slide 52

Slide 52 text

FlatMap() List of all tweets from all twitter handles

Slide 53

Slide 53 text

Let us take a closer look at this

Slide 54

Slide 54 text

Observable.fromIterable(twitterUsernames()) @ haroldadmin @ gpeal @ jakewharton A stream of Twitter handles

Slide 55

Slide 55 text

Observable.fromIterable(twitterUsernames()) .flatMap(twHandle -> tweets(twHandle)) @ haroldadm i n @ gpeal @ jakewharton twHandle -> tweets(twHandle) ... ... ... ... ... ... ... ... ...

Slide 56

Slide 56 text

@ haroldadm i n @ gpeal @ jakewharton Som e Tweet Som e Tweet Som e Tweet ... ... ... ... ... ... ... ... ... (Observable of Observables) (Flattened to a single Observable)

Slide 57

Slide 57 text

FlatMap does not preserve the order of emissions. If the ordering is important, then ConcatMap should be used instead.

Slide 58

Slide 58 text

There is a huge amount of operators. Each one serves a specific purpose.

Slide 59

Slide 59 text

There is documentation on what every operator does. Go nuts using them in your streams.

Slide 60

Slide 60 text

Let’s move on to threading in RxJava

Slide 61

Slide 61 text

Threading Jumping threads between Streams

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

Switching threads

Slide 66

Slide 66 text

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:

Slide 67

Slide 67 text

ObserveOn() may be called as many times as required to change threads in a stream.

Slide 68

Slide 68 text

SubscribeOn() should only be called once. Subsequent invocations have no effect.

Slide 69

Slide 69 text

Switching threads is easy with RxJava. It is dramatically simpler than other async utilities presented earlier.

Slide 70

Slide 70 text

There’s a slight problem here though. None of the examples presented so do any work.

Slide 71

Slide 71 text

The reason? Observables are cold streams. We have only applied operators to streams so far, but never actually subscribed to any of them.

Slide 72

Slide 72 text

Observing Streams Adding observers

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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.

Slide 75

Slide 75 text

Observing Observables

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

Managing subscriptions is important on Android. We must cancel our subscriptions when we don’t need them anymore, or else they will waste resources.

Slide 78

Slide 78 text

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.

Slide 79

Slide 79 text

To be able to cancel a subscription, we need to hold on to this disposable.

Slide 80

Slide 80 text

Disposing a disposable

Slide 81

Slide 81 text

Providing an onError() method is equally important. If our stream encounters an error and does not have an onError() handler, our application will crash.

Slide 82

Slide 82 text

One more thing...

Slide 83

Slide 83 text

Side effects Affecting the world outside the stream

Slide 84

Slide 84 text

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.

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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.

Slide 88

Slide 88 text

Side Effects

Slide 89

Slide 89 text

That’s a wrap on RxJava

Slide 90

Slide 90 text

Dagger Compile time Dependency Injection

Slide 91

Slide 91 text

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.

Slide 92

Slide 92 text

But wait, what is dependency injection?

Slide 93

Slide 93 text

Dependency Injection

Slide 94

Slide 94 text

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.

Slide 95

Slide 95 text

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.

Slide 96

Slide 96 text

Let’s look at an example

Slide 97

Slide 97 text

A simple Cache

Slide 98

Slide 98 text

A NetworkService relying on the Cache

Slide 99

Slide 99 text

Our NetworkService class has a dependency on a Cache. Let’s take a closer look.

Slide 100

Slide 100 text

Dependency Injection

Slide 101

Slide 101 text

Dependency Injection

Slide 102

Slide 102 text

We don’t want to create our dependencies ourselves. We want them to be provided to us.

Slide 103

Slide 103 text

Dependency Injection

Slide 104

Slide 104 text

Dependency Injection ...But why?

Slide 105

Slide 105 text

Because now we have made our Network Service more flexible. Suppose we have multiple implementations of our Cache.

Slide 106

Slide 106 text

Implementations of Cache

Slide 107

Slide 107 text

Implementations of Cache

Slide 108

Slide 108 text

Dependency Injection If we create the Cache ourselves, we lose the flexibility to use multiple implementations easily

Slide 109

Slide 109 text

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.

Slide 110

Slide 110 text

But now we just shifted the responsibility of creating the dependency somewhere else.

Slide 111

Slide 111 text

Now the class which uses MyNetworkService will need to create a Cache and give it to us.

Slide 112

Slide 112 text

And that is okay.

Slide 113

Slide 113 text

But it’s annoying.

Slide 114

Slide 114 text

Luckily, Dagger is here to help us.

Slide 115

Slide 115 text

Dagger Annotate the constructor with @Inject, and dagger will take care of providing the dependency to us

Slide 116

Slide 116 text

@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.

Slide 117

Slide 117 text

There are two kinds of dependencies: Internal and External

Slide 118

Slide 118 text

Dagger can handle internal dependencies on its own, because we annotate their constructors with @Inject

Slide 119

Slide 119 text

But what can we do about external dependencies?

Slide 120

Slide 120 text

Dagger Modules

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

External dependencies

Slide 123

Slide 123 text

Providing External Dependencies

Slide 124

Slide 124 text

Using Modules, we can tell Dagger how to create and satisfy external dependencies in our app.

Slide 125

Slide 125 text

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.

Slide 126

Slide 126 text

We can get instances of our dependencies in Activities/Fragments using Field injection.

Slide 127

Slide 127 text

Field injection

Slide 128

Slide 128 text

But where does the inject() method come from?

Slide 129

Slide 129 text

Dagger Components

Slide 130

Slide 130 text

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.

Slide 131

Slide 131 text

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.

Slide 132

Slide 132 text

Dagger Components

Slide 133

Slide 133 text

Components need to be initialized before we can use them. Most commonly they are initialized when our Application starts.

Slide 134

Slide 134 text

Component Initialization

Slide 135

Slide 135 text

Once a component has been initialized, it can be used for injection.

Slide 136

Slide 136 text

Injection

Slide 137

Slide 137 text

And that’s a wrap

Slide 138

Slide 138 text

There is a lot more to learn about Dagger

Slide 139

Slide 139 text

We can not possibly go through everything today

Slide 140

Slide 140 text

I hope you now know enough about it to not be intimidated by it

Slide 141

Slide 141 text

Live coding Demo https://github.com/dsc-dtu/Dogs-Rx-Dagger

Slide 142

Slide 142 text

RxJava and Dagger @haroldadmin @haroldadmin Kshitij Chauhan kshitijchauhan.me Sample App: https://bit.ly/2QhZvTJ