(upbeat music) - Okay, so this talk, well first, let me start, how many people are familiar
with what RxJava is? How many people currently
use it in their app? Okay. I'm going to start with kind of a little introduction about why
reactive is becoming such a big thing on Android, and I'm going to do that
through kind of talking about some concepts of why we
need to think reactively, and then we'll start moving into RxJava, and how it actually helps us
model these things in our apps. I will specifically be looking
at examples using RxJava 2, which is coming out in about a month. All right, so, why is Reactive suddenly becoming
something that, you know, you hear a lot of people talking about, you see a lot of people starting to use? I'm going to postulate that, unless you can model your entire system of your app in a synchronous faction, having a single asynchronous source will ultimately break the traditional imperative style of
programming we're used to, and that's not break in the
sense that it stops working, it's break in the sense
that it really pushes a lot of the complexity onto you, and you start losing the things that imperative programming
is actually really good at. Let's look at this through an example, to kind of understand why I think this is such a big problem. Start with a simple class
that can get us a user object, and has some mutaters on it. Now, if we are living
in a synchronous world, a single threaded world, we
can use this totally fine, and we can rely on it to
be exactly as we expect. Create an instance, print out the user, modify some of its properties,
print out the user. This behaves exactly as you would expect. The problem comes when we have to start modeling things in
an asynchronous fashion. Let's say that, when we
change these properties, we now need to reflect
them on the server side. These bottom two methods now
need to become asynchronous. How would we change our code
in order to reflect this? One thing you could do is nothing. You can basically just assume
that the asynchronous call to update the server will succeed, and you can make the change locally, so that it's reflected instantly when we print out the user object. Obviously, this is not a good idea. Networks are flaky, the
server might return an error, and now you have to reconcile dealing with your state locally. We could do simple things
like maybe providing a runnable that gets called whenever this async call succeeds, and now we are actually
kind of being reactive, where we are only updating
the data that is displayed when we are ensured that it
was asked successfully changed. However, we aren't modeling
any problems that could occur, like if the network ends up failing, so maybe we create our own listener, so when an error actually does happen, we can do something with that, we could report it to the user,
we can automatically retry. Stuff like this works, and
it's what people usually, the avenue people go
down when they need to mix in asynchronous code with code that's just kind of
running on a single thread, which is traditionally
an Android main thread, but where the problems start arising is when you really have to do more, you have to support
multiple calls happening, the user is changing, you know, multiple properties in your
app while filling out a form, or maybe there is like flows
of these asynchronous calls, where the success of the first one has to then trigger
another asynchronous call, which can also succeed, or fail. We also have to remember that this is in the context of Android, and so there's a lot of
additional considerations that we have to take into account. For example, in our success callback, maybe we are propagating
information directly into the UI, but I haven't really
defined whether or not, or sorry, the problem here
is that activities on Android are ephemeral, they might
disappear at any time. Either you a phone call,
and your app disappears, maybe the user presses home,
or simply they press back, and so if this asynchronous call returns after the UI has been torn down, you're going to run into problems. Now, there are imperative
ways to work around this. We can, you know, checksum state before we end up modifying the
view, so that's not too bad. We also have this, we are
creating this anonymous type, and so this will ultimately lead into a short-term memory leak, because it's going to retain
a reference to our activity, and if that activity disappears, the asynchronous call is still
happening in the background. If you want to know more about
why this is such a big deal, Pierre is giving a talk later
today about memory leaks, which I encourage you to go to. The last thing is that we didn't define what threads these
callbacks are running on. Maybe they come back on
the background thread, and so now it becomes our responsibility to imperatively write a code, write code that does the thread hopping
back onto the main thread. We've cluttered this activity with a bunch of things
that are really unrelated to the intent of the code, which is simply to start
this asynchronous work, and handle the asynchronous result, and so this is only setting, you know, eagerly calling this asynchronous request. We are not dealing with things
like disabling user input, handling, you know, button
clicks, multiple fields, so when you have code like this that deals with only the simple case, and then suddenly you start
to turn it into a real app, all these problems compound, and you are left with
managing a bunch of state, a bunch of checks in your activities. This is why we need to
think reactively in our app, because everything in it essentially is in some way asynchronous. It's asynchronous by default. We have our network, which
we are sending requests to, and whose responses or returning after a large period of time. We can't block the main thread for that, so it has to be done
in a background thread. We have things like the file system, whether it's databases writing to storage, even shared preferences, where we can't block the
main thread for that, so we have to do them
on background threads. The user is also somewhat of
an asynchronous source of data. We push data to them in the UI, and then they react using button clicks, or maybe changing inputs in text fields, and those things happen asynchronously. We are not synchronously
pulling user for data, we are waiting until they do something. This just goes to show that, basically, the UI is another piece. A lot of people think that you can write these single threaded apps, which by default are on the main thread, but really the UI is a piece
of asynchronous source. Even if you don't have the data component or the network component, the user itself is an
asynchronous piece of information. You have to react to their input in ways that make sense to them. Here is just an example of a bunch of data flowing through the app, and this is not all happening synchronously. These things happen
based on network speeds, happens on disk speeds, happens when the user's clicking buttons. It's just data that's flowing
to the app at different times, and the app has to be
receptive, and reactive to that, so that you don't wind up in a state where either the main thread is blocked, or some piece of data
comes in asynchronously when you weren't expecting it, and the app either doesn't
reflect it, or just crashes. Ultimately, your code in the middle here is what's responsible
for managing everything. This is where the
complexity ends up lying. You have to maintain all this state in your activities fragments or whatever to reconcile the fact that these multiple asynchronous sources are producing and consuming data at potentially different rates. That doesn't even take into
account Android itself. Android is a fundamentally
asynchronous platform. We have things like push notifications, we have broadcasts throughout the system, even things like a configuration change, when the user rotates the
device may come at any time, and if your code is not expecting
that to come at any time, you will run into crashes, and you will run into cases where the app just starts misbehaving, because some state got into
a certain configuration where your app just
completely stops reacting. Just to go back to this point, if I'm postulating that a
single asynchronous source ends up breaking imperative programming, if Android by default is
something asynchronous, we have network requests, hard to find an app
without network requests, that's fundamentally
asynchronous, you have the disk, and the database, a fundamentally
asynchronous source, and then the UI itself should
ultimately be thought of as an asynchronous source, so by default, basically everything in Android
is already asynchronous, so by clinging to more
traditional imperative programming and state management techniques, you are ultimately harming yourself. What we need to do is take this model, where our code sits in the
middle, as the arbiter of state, and trying to coordinate all
these asynchronous things, and instead of having that, we can remove our responsibility by hooking these things up directly. We can change the UI to subscribe
directly to the database, and just react when the data changes. We can change the database, and the network call to just react when the button is clicked,
instead of us having to receive that click, and then dispatch it. Similarly, the network
response comes back. It would be nice if that
just updated the data, and we know now that
when the data updates, the UI automatically updates, and so we removed our
responsibility for doing that. If Android does something asynchronously, like starts rotating, sends a broadcast, it would be nice if that was
just automatically reflected in the UI, or automatically
started or stopped some background job. Ultimately, this removes a lot of the code that we had to write in order to maintain those states ourselves. We are still writing code,
there's still code here, but all we are doing is now
connecting the bits together in a way that makes sense, instead of trying to manage
the state of all of them, emitting and consuming events. Ultimately, this is
where we get to RxJava. This has become de facto of
reactive library for Android, mostly due to the fact that it was one of the first available for Java
that was really comprehensive, and also, for RxJava 2, because it retains support
for older versions of Java that we need on Android. It comes down to providing
three major things. It's a set of types for
representing the sources of data. Then, we have a set of types
for subscribing to that data, and listening to when it changes. Then finally, the most powerful part is a bunch of methods which allow you to combine, compose, transform that data so we can end up creating those links between the different
asynchronous sources of data, and the things that want to
subscribe and display it. Let's start with looking at what the first to look like in the API. A source of data, usually
what will happen is it will start or stop doing some work when you start listening to it. You can think of this
like a network request that's not going to fire until you start listening for a response, and if you ultimately end up unsubscribing from that source of data
before it completes, it could potentially do work by saying canceling the network request. These can be both
synchronous and asynchronous, and so you can model something
like a network request, which is blocking, but running
on a background thread, or it can be asynchronous,
which is something like, something like calling out to Android, and expecting an activity result, or even like clicks in the UI can be thought of as asynchronous. You are not blocking, waiting for a click, you're just reacting to the
fact that the click happened. Usually these can produce a single item, or perhaps many items, and so, like a network response
would be like a single item for a single request, but a stream of button clicks
would be potentially infinite, as long as your UI is there, even though you're only, you know, subscribing to a single button. These also can be empty,
and so there is the idea of a source that really
only succeeds or fails, and doesn't actually have any items. You could think of this
like writing to a database, or writing to a file. It doesn't really have a response. It doesn't really have
an item that it can, you know, return to you, it really just kind of completes or fails. That completion and failure aspect is actually modeled by sources in RxJava with these so-called terminal events, which are, it either completes
successfully, or it errors. This is similar to, you
know, a method that can return normally, or throw an exception. It also may never terminate, so to go back to the button click example, if we were modeling button
clicks as a source of data, that will never end as
long as your UI is there, and when your UI disappears, you are probably unsubscribing from that source of button clicks,
it's not actually completing. Really, this all amounts
to just an implementation of the traditional Observer pattern. We have some thing that can produce data, and then we have a contract
what the data looks like, and all we are doing is just
wanting to observe that. We want to add a listener to it, and get notified when things happen. The two main types that
are going to represent this in RxJava 2 is Observable, and Flowable, and is both actually end up
modeling the same types of data, and that can be zero to N items, so it can be empty, you know,
it can have a single item, or potentially many, and then they terminate
either successfully, or they terminate with an error. Why do we need two types represent the same structure of data? This comes down to something
called backpressure. I don't really want to dive into too much what backpressure is,
because it's a complex topic, but I'm going to try
to show you an example, which should illustrate the difference. Backpressure is there to allow you to slow down a source of data. You know, we are living
under these systems that have finite resources, and you can only process
so much at a time, backpressure is a way to basically tell all of the
people sending you data to slow down, that you can't process it as fast as they are sending. RxJava 1 had backpressure, but it was implemented fairly
late in the API process, and so every type in the
system had backpressure, instead of RxJava 2,
where we have two types. Where this became a disadvantage is that, while all types expose
the idea of backpressure, the idea that you can slow them down, not all sources actually implemented it, so you would ultimately get a crash, that it was unsupported at runtime. This is because
backpressure, like, you know, like inheritance, you have
to really design for it, it has to be a thing that
you account for upfront, instead of something that
just gets mixed in later, and this is really why we have two separate types in RxJava 2, because you can now
dictate in the type system whether backpressure is supported or not, because if it's not, that's
something that's fine, but it's also something that
you need to expose in the API. The example that would show this is, if we have a source of data
which is, say, touch events, the user puts their finger on the screen, and they drag it along, and this produces a
series of touch events. Now, this is something that
we can't really slow down, we can't really tell the user, you know, draw half of your curve, and then stop and wait while I catch up drawing, and then you can continue
the rest of your curve. We can potentially do
this through other ways, such as like disabling buttons, and displaying other UI
to try and slow them down, but the source of data itself is not one that can be slowed down. If the already drawn that
curve with a bunch of events, we can't tell the system
to slow down sending them. You can compare that to
something like a database where we have a large result set, and maybe we only want to pull
out certain rows at a time. Say, oh, I only want the first four rows, okay, now give me three more rows, okay, now give me five more rows. A database can model this really well, it has the concept of cursors, but a touch event, a
stream of touch events can't model this at all, because there's no way to push back, and slow down the user's finger. In RxJava 1, you would see both of these types
implemented as observables, and what would happen is, at runtime, you might try and apply backpressure, and you ultimately get an
exception, and your app crashes. This is the reason why, in RxJava 2, we model them as different types, because one fundamentally
can support backpressure, and one fundamentally cannot. There are ways of
converting between the two, which is basically just
applying a strategy of how backpressure works, but I'm not going to go into that. Because these are two different types, they have to expose this
backpressure in some way, but because they also model
the same type of data, they also have to kind
of appear the same way in terms of how data gets
pushed into your callbacks. The two interfaces for listening to events from these sources
look fairly similar. The first method is called onNext, and this is the method where items are going to be delivered, and so as long as there
is one or more items being produced by the
observable, or flowable, this method will be called for each one, allowing you to do whatever processing you want to do with the items. This also could be infinite. I talked about infinite
observables, like button clicks, so if you are listening to a button click, this onNext method will
basically be called every single time the
user clicks a button. For non-infinite sources,
sources that actually end, we have those two terminal events. They either can complete, where complete and dictate success, or they can error, where error indicates
that either processing the onNext callback resulted
in an exception being thrown, or that the source of data, where we are listening to events from, had a problem, and had
to deliver an error. Both onComplete, and onError are what's called terminal events, which means you will
never get another callback after you get either one of those. Where they differ is in this last method, called onSubscribe. If you know RxJava 1, this is
something that's fairly new. It's basically the idea
that when you subscribe to either an observable, or a flowable, you are really creating a like a resource, and resources often need cleaned up when you're done with them, and so this on subscribe callback will be immediately called as soon as you start listening to an
observable or flowable, and it's going to hand you
one of these two types. For observable, with this
type allows you to do is call the dispose method,
which essentially says, I am done with this resource, I don't want any more callbacks, and so what if we have, you
know, a network request, this would potentially
cancel the network request. If you are listening
to that infinite stream of button clicks, this would basically
say that you no longer want to receive those, and it would onSet the
listener on the view. Now, the same is true
for the type onFlowable. Even though it has a different
name, the use is the same, it has this cancel method
which is essentially the same as disposable's dispose. The difference here is
that it has a second method called request, and this
is where backpressure shows itself in the API. This request method is how you tell the flowable that you want more items. I'm going to build up a little chart here of how these things relate to each other. We basically can represent and the, you know, any type of emissions. It could be zero, it could be one, it could be many, and it
potentially could complete, or potentially error. The only difference between the two is that one has backpressure,
and one does not. Just really quickly, I want to touch on why the disposable and subscription types are named so differently,
and why their methods, one is dispose, and one is cancel, instead of perhaps being, you
know, one extending the other, and just adding the request method. The reason is because there is this thing called the reactive stream specification. It's basically an initiative
where a bunch of companies got together, and said, let's make a standard set of interfaces for reactive libraries in Java, and they wound up with these four classes, for interfaces rather. You will see the subscriber type, and the subscription
type in the middle there. These are actually part
of the specification, and so that's why they have
a name that is so different than the ones, the disposable type, and the observer type. They are different because
they are part of a standard, and we can't really change that. The advantage though is that,
because it is a standard, although this doesn't happen
frequently on Android, but if you had to use two
different libraries for streams, if they both implement the standard, you can convert between them seamlessly. I'm going to change my left column here to actually be types that implement the reactive streams specification, and the types on the right are, which implies that
backpressure is supported, and the types on the right are those which do not have backpressure. If we go back to our user manager, before, we were kind of pulling
users out of this class, and then displaying them when we thought it was most appropriate. Now we could do is model this as, instead, a observable of user. It's a source of user objects that, whenever the user changes, will
be notified of that change, and can react to the
change by displaying it, instead of trying to guess when the most appropriate time is, based on other events
happening in the system. There's a couple specialized
sources in RxJava, and it's basically a
subset of the observable, so there's three of them. First one is called single. Designer has a single item, or an error, so it's less of a stream, and more just like a
potentially asynchronous source of a single item, and it also
does not have backpressure. The way to think about this
is kind of like a scaler. You call a method, you get a turn type, you get a return value, or that
method throws an exception. Single essentially
models the same concept. You subscribe to a single,
you either get back your item, or you get an error. The difference being that it's reactive. Completable is similar to a method that declares a void return type. It completes with no data, or it throws an exception, has an error. Kind of think of this
as a reactive runnable, it's a set of code that you can run, and it will either complete
successfully, or fail. A new type in RxJava
2, compared to RxJava 1 is called a maybe. This either has an item, errors, or potentially has no items. The way to think of this is
it's kind of like an optional. A method that returns an optional value will always return something, if it doesn't throw an exception, but that optional may
or may not have a value. We will see where these are
going to be used in a second, but this is similar to
the optional concept, except just reactive. There's no types that actually model that that are reactive streams
compliant in RxJava 2, they are only modeled in the observable and backpressure-free side. If our setName and setAge
calls are asynchronous, they either complete or fail,
they don't really return data, and so what we want to do is
model those as completable. I'm going to go through
this really quickly, just to show how the sources are created, and how you can wrap the things that you are already
using in reactive sources. All of the types have static methods that allow you to create
them with like scaler values. You can also create them
from things like arrays, or anything that's iterable, but there's two that are really useful that I think are going to be the most used for adapting the methods, and the actions that
you are already doing, in either a synchronous,
or asynchronous way. The first one is called fromCallable. FromCallable is essentially modeling some synchronous behavior
that returns a single value. In this case, I'm delegating
to some hypothetical method, called getName. The nice thing about fromCallable is that you are allowed to throw an
exception from a callable, which is a standard Java interface, and this means that we can model things that would potentially fail
using a checked exception. If we have an HTTP request
that we want to make which could throw an I/O exception, we can now put that inside a fromCallable, and the returned observable, when subscribed to, will
execute that request, and if that request throws an exception, we will get an on error,
if that request completes, we will get the response, an onNext. FromCallable is available
on all five types. These are for modeling synchronous sources of a single piece of data. It's what you would use a method
for in an imperative world, a method that returns a return value. In the reactive world, fromCallable is what you use to model that. There is also two
additional methods on both, maybe and completable, and those allow you to model things that don't return a value. Like I said, basically just a runnable, except that runnable is now reactive. The most powerful method
for creating observables is aptly named create. If you use RxJava 1,
you may know that create is this horrible method that you really should never be using in RxJava 1. In RxJava 2, that's been fixed, so that the create method is actually one of the most useful methods, and should be used for wrapping sources. We create it with a callback. This callback it's called whenever there's a new subscriber, and we are given this
thing called an emitter, and the emitter is basically just the person that is listening. We can take data, and we
can send it to the emitter. In this example what I'm doing is I'm just sending a piece
of data synchronously, and then I'm completing the stream, because it completed successfully. I'm going to convert this to a lambda, to clean up some of the boilerplate here. So, I can send more
than one piece of data. Unlike fromCallable, I have the ability to call next multiple times. Oh no! The other advantage of this is that we can now model
asynchronous pieces of data. If I take HTTP requests, and instead of executing it synchronously, executed it asynchronously, I can call that onNext
method in the emitter, from the HTTP callback. Another nice advantage
of this create method is it allows you to do things
when the person unsubscribes. If someone stops listening
to the HTTP request, there's no reason for it
to continue executing. We can now add a cancellation action, which cancels the HTTP request, and cleans up the resources. This is also super useful for Android, because it's how we model
interactions with the UI. When you subscribe to an observable, we want to say start
listening to button clicks, and then when you unsubscribe, we want to remove that listener, so we don't end up, you
know, leaking a reference, leaking that reference to the view. Creating observables works on all, or, creating observables with this emitter works on all five types. Let's quickly look at observing sources. I showed these two interfaces earlier, and I showed that fourth method, which is kind of new,
and is a little weird. You actually don't use
these interfaces directly when you subscribe to an observable, subscribe being the method
that starts listening. Because of that fourth method, you are put in a weird place where, well, what do I do with this object, and how do I, you know, unsubscribe? Instead, we have a type
called DisposableObserver, and this will automatically handle that fourth method for you, and allow you to only be concerned about the actual notifications from the observable itself. But, how do we dispose here? If we no longer have that callback, how do we unsubscribe, how do we tell the resource
that we want it to go away? One thing you could do is
hold onto that observer. It actually implements disposable, so you can call dispose method, and it will take care
of forwarding it to you, you know, up the chain, but there's a new method in
RxJava 2, called subscribeWith. This allows you to use it in a similar way that you would do if
you are using RxJava 1, which is that it now returns you the thing that you can then call dispose on. In RxJava 1, this is
called a subscription. It's also called a subscription
in the flowable world, but in the observable
world, it's a disposable. For people that know of
composite subscription, there's a composite disposable, and this basically allows you to subscribe to multiple streams, take those returned disposables, and add them to what is
essentially a list of disposables, and you can unsubscribe from
multiple streams at once. You will see this a lot on Android, where you have a single
composite disposable for, you know, an activity,
a fragment, whatever, and you are unsubscribing in the, you know, onDestroy, or whatever lifecycle callback is most appropriate. You have these on all four
non-backpressure types, the one that use observer, and there actually is one on flowable, even though flowable uses
the subscription callback, not the disposable one. The type we provide in
RxJava 2 actually allows you to model it in the same way, so you get a disposable
back from all five types, even though flowable is kind
of a little bit different. The way to think of this is like you would think of
anything that is a resource, a file, a cursor on a database, you wouldn't open a file without having some way to close it, you wouldn't open a cursor on a database without eventually closing it. Never subscribe to an observable without managing the disposable, and ultimately, unsubscribing from it. Okay, so those were the types, let's really, really quickly look at the methods that allow you
to compose, and change data. We call these operators, and
they do basically three things, manipulate or combine data, they change the threading semantics, or they can start and stop emissions. We are really only going
to look at the first two. Just like we took something
that was imperative, like a synchronous method
call, and turned it reactive, operators basically do the same thing. Here, we are applying an
operation to a string, and getting back a new string. In the reactive world, we
would have an observable, and we would apply that
operation via an operator. In this case, map is the operator, which is allowing us to
take data being emitted, and apply some operation to it to create a new type of that data. I'm actually going to skip this one. If we look at our user object, we defined that, originally, the callbacks were coming
back on a background thread, and we had to explicitly
move to the main thread. There's actually a built-in
operator that allows you to do that, and allows you to do it at a much more declarative way. We can say, I want to observe emissions from this observable,
on a different thread, and so the things coming
from user would be on the background thread, but the things coming
out of main thread user will now be on the main thread. ObserveOn being the operator here. Because we're changing threads, the order that you apply these
operators really matters. Similarly to observeOn, we can change where the work of the observable happens. So, if we are doing a network request, that network request is still going to be done synchronously, but we don't want it to
happen on the main thread, so what we do is we can apply an operator that changes where we
subscribe to the observable, and where we subscribe is
work ultimately happens, so now, when we subscribe
to our background response, it will change to the background thread, I/O is just a thread pool
of threads you can use, and so it will do work
on that thread pool, and then send out the notification
to whoever is listening. SubscribeOn here being the operator to change where the work happens. What's nice is that,
because these all return, you know, a new observable, and all these methods exist on observable, we can compose them,
and chain them together, so what you normally see is that we don't have intermediate
variables for these, we are just applying the
operators in a certain order. We want a response, or sorry, we want to request execute
on the background thread, we want to observe the
result of that request on the main thread, and we want to, say, change the response into, you know, a string, we want to read the string. Except, again, order here matters. Because I applied the map
operator after observeOn, that's going to run on
Android's main thread, and we don't want to be
reading from an HTTP response on the main thread, we want that to be happening before we change to the main thread, and so the request comes
in, and it, you know, emits the response down
the observable chain, we map that into the result string, and then we change threads
to the main thread, where we can ultimately
subscribe, and show it in the UI. Then, there's other operators, I skipped flatMap, so
I'll just skip it here. Where we see some of those other types, you will notice that
these were all observable. There's other operators which
actually take observable, and return it into a different type, and so an operator like first is going to take the first element
that's emitted from a string, and return it to you. In RxJava 1, we got back and observable that only emitted one item. This is kind of weird, because
if you have a list of items, and you call get on it
to get the first item, you don't get back a
list with only one item. What you get back is the
scaler, and we know that, well, now we have a type
that models the scaler, in the reactive world, so, in RxJava 2, when you call this first operator, which is guaranteed to
only return one element, you get back a single. If the observable is empty, this will actually result in an error, because we know a single
either has an item, or errors, and those so there's other
operators like firstElement, which is actually going
to return you now a maybe. When the observable is empty, maybe can actually model that by completing without an error. There's ones that also return completable, so if you are just ignoring the elements, all you care about is whether
it completes or fails, that now returns completable, and that's exactly what
completable models. All these exist on flowable as well, so they all have the same operators, they all return the
same specialized types. This is a chart that kind of
shows some of the operators, and the upper right-hand corner of this is basically where the types narrow, so when you call something, like you want to count the
number of items in a stream, account is always a single value, so you get a narrower type, like single, and then we also have operators
which do the opposite, which is, you know, take a type, and turn it into something more broad, so you can take a single, and
turn it into an observable. Okay, back to our original example. If we want to be reactive with it, we can, you know, subscribe to our user, say, I want notifications
on the main thread, and then I want to shove that into the UI, display that user. Anytime the user changes, this code is automatically going to run, you are automatically
going to see updates, and we no longer have to worry about managing this ourselves. However, we do have to remember to manage the disposable that gets returned, because we are in the Android world, and when our activity disappears, we want this code to stop running. In onDestroy, we would,
you know, dispose of this, dispose of the disposables. Similarly, when we ultimately make an asynchronous request to change data, we want that to happen
on a background thread, we want to observe the
result of the main thread, whether it succeeds or
fails, and, you know, in the success callback,
we could, you know, essentially reenable the
text box or whatever. Again, because you wouldn't
open a file without closing it, you wouldn't subscribe without
managing the disposable, so we had this to our disposable list. I'm actually going to skip this, just because I'm a little low on time, but a nice thing about RxJava 2, compared to RxJava 1 is that there's a fundamental architecture shift. What that affords, on
Android specifically, is that there's just
less intermediate objects being created, so when
you create these streams, every operator you call has
to return a new observable that implements that behavior. When you call map, you
get a new observable that takes the old one, runs a function, and, you know, emits the new data, and so that requires a bunch of objects, intermediate objects to be allocated in order to model that stream. RxJava 2 actually changed
how this works in a way that we actually get less
intermediate objects created. Oops, I wanted to. You get less allocation to
actually create the stream, which is call the operators. Each one actually results in
one less object being created, and there's also less overhead
when subscribing to a stream. There's less method
dispatch that has to happen, and so ultimately what we
get is the faster, less GC, causing less GC version of the library, without any compromise in the API. So, RxJava 2 is basically this idea that we want to take these things, which are fundamentally
asynchronous in Android, whether it be the network, Android itself, database, even the UI, modeled
as an asynchronous source, and write code that reacts
to changes in these sources, instead of trying to cope with changes, and manage state ourselves. Right now, it's in a
developer preview release, so we are basically finalizing the API, and in about a month, it
will have its final release, where it will be available, I mean, it's already
available to put in your app, but the API might change, and the final release solidifies the API, so that things like
libraries can start using it, and exposing these types automatically. If you do use RxJava 1, there's actually a project which allows you
to convert between the types, and so this will allow you to
incrementally update your app. If you are interested in
that, here's the link. Your dependencies for that
will ultimately look like this. Where I want to end is basically, RxJava 2 is not something new, reactive programming is
not new, by any stretch, but Android itself, for whatever reason, is this highly reactive world that we've been taught to model in a very imperative, stateful fashion, and just try and cope with the fact that we have to manage all
these things ourselves, and reactive programming, and RxJava in general
allows us to model it in the proper way, which
is that it is asynchronous, embrace the asynchronicity of the sources, and instead of trying to
manage all the state ourselves, compose them together, such that our app becomes truly reactive, and now, really all we are concerned about is how to build those arrows, and is not actually how to
manage the state of the data that's flowing through the system. That's all I have for you. Thanks everyone for coming. (applause)
It's a great talk.
p.s. Maybe it's just me - it feels like the community is going away from RxJava (looking at LiveData + Coroutines) or at the very least trying to limit its usage to the minimum.
FYI, here's the talk's ABSTRACT
Development on the next major version of RxJava is underway. While the operators remain largely unchanged, Observable creation, subscription management, and backpressure has been completely overhauled in this new version. This talk will be an exploration on not only what has changed but also the reasons behind why these changes were made. We'll also talk about how both libraries and applications can migrate to supporting RxJava 2 as well as interop between the two versions. No prior knowledge of RxJava is strictly required, although concepts, terms, and comparisons will be made that do assume some prior knowledge.
switchMap