Exploring RxJava 2 for Android • Jake Wharton • GOTO 2016

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

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.

👍︎︎ 14 👤︎︎ u/KitchenWeird 📅︎︎ Feb 19 2019 🗫︎ replies

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.

👍︎︎ 2 👤︎︎ u/goto-con 📅︎︎ Feb 20 2019 🗫︎ replies

switchMap

👍︎︎ 1 👤︎︎ u/ursusino 📅︎︎ Feb 21 2019 🗫︎ replies
Captions
(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)
Info
Channel: GOTO Conferences
Views: 109,180
Rating: 4.9484477 out of 5
Keywords: GOTO, GOTOcon, GOTO Conference, GOTO (Software Conference), Videos for Developers, Computer Science, JakeWharton, Jake Wharton, Square, IT, Software, GOTOcph, Android, RXJava2
Id: htIXKI5gOQU
Channel Id: undefined
Length: 44min 15sec (2655 seconds)
Published: Thu Oct 27 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.