Leveraging Android Databinding with Kotlin
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Davies, Ash
Android databinding is considered as both a powerful toolchain empowering your views with access to view data without the necessity to build cumbersome presenters and conversely as an overly complex convoluted mess of binding statements opening the door to unnecessary irresponsible domain logic in your view layouts. Whilst the latter of these statements can be true databinding offers a very powerful code generation syntax allowing you to utilise the power of the compiler to ensure that your binding statements are runtime safe. Combining this with the terse syntax afforded by Kotlin allows us to dramatically cut down on boilerplate and build complex user interfaces with relative ease. In this talk you can learn how to utilise extension bindings and property delegates with your layouts and manage your screen state transformations with true and safe two-way binding allowing you to build a fully reactive observable view layout.
 So I'm Ash Davis. I'm working with Immobilienskirts. And I'm talking about leveraging Android data binding with Kotlin. Now, there's a lot of topics to get into here. And I've only been able to cover a partial part. But I really encourage you to check these out. So let's start off. What is data binding? Data binding is a support library that allows us to bind UI components to data sources declaratively rather than programmatically. It's potentially really powerful and complex, but use effectively it can really cut down on presentation boilerplate. So it started off with data binding beta in 2015 when Google announced it after IO. It's a support library that can be used right back down to Android 2.1, which is API version 7, to write declarative layouts and minimize the glue code required to use application logic and layouts. As of Android's Gradle plugin 3.1, it includes the new data binding compiler, so data binding version 2. This includes incremental class generation. So this means it will speed up your build time a little bit, and it will have pre-compilation of classes, which means that your data binding classes will actually be available prior to your first build. If you've used any annotation processes that generate classes that you rely on at runtime, you'll know this is an absolute pain. So it's nice to have these even if your build buggers up. So let's start off with a basic activity and see how we can start using data binding with this. This is just a basic activity how it might start off with. So first, we want to make sure we replace the framework set content view with that of the data binding utility to retrieve a binding class that has been generated for us that we can refer to in our programming code. Also, as of the Android Gradle plugin version 3.1, data binding is life cycle aware. This means we need to inform the binding of our lifecycle owner so it can manage the subscription accordingly. So this is already pretty basic. So how can we use Kotlin to improve this? Let's start with the binding. So Kotlin allows us to use delegated properties. This business cat delegates. So with delegate properties, we can create a getter and set a template to define how we want to use this resource. And we can reuse it as many times we'd like in different places as long as it makes sense. So for example, a delegated property would be our Kotlin lazy delegate. Here you can see the sample from the documentation where computed would be referred only once. And then the hello value would actually be referred every time we then gone to access it. So Kotlin gives us two interfaces to use when we want to create our own delegate properties. We have the read only property and the rewrite property. These are for value properties and for variable properties respectively. So one is immutable and one is mutable. And we have to implement these methods to actually provide the functionality. So for our delegate property for our activity binding, we want to make sure that we're actually using a immutable property, so the read write property. Here we have just a basic class and want to add our implementation to this. So you can see that the receiver is the activity, meaning that for this property delegate, it has to be made from an activity so we can use the reference activity. We pass in the resource ID for the layout. And we want to lazily instantiate our binding so that we'll refer to the same one in the same way that we'd use with lazy. How does this look like in our activity? So we can use an extension function as well to access our delegate property. This is consistent with how we do so with a lot of other Kotlin delegate properties, like lazy or observable, so that it looks quite nice and consistent in our code. So let's introduce some architecture in here so we can actually get some business behavior. In last year's Google I.O., Google announced the architecture components to start building framework applications quickly and easily. And again, this year's Google I.O. They announced Jetpack components so we can get even more in there. This includes live data and view models and a sort of unofficial endorsement of using model view view model as a paradigm. So it wasn't an instruction to migrate your existing architecture over from MVP or from MVI or for one of you have to MVP MVVM sorry. But it was an indication that this is what you can use if you've got a fresh project or if you're starting from scratch. But data binding works really well with MVVM because the view passively observes the view model and it doesn't really matter if the view is there or not. So we don't have to worry about unregistering a listener or making sure our view is nullable or hiding all these because we can have many or no listeners on our view model view model properties. And the lifecycle components react accordingly. So the view model state is bound by view observation. And the view model notifies the view notifies the view model of UI events, user interactions. I could probably talk all day about how MVVM works, but this talk is about data binding. So let's move on. So this is our activity as it was before. And we need to actually apply our model to our binding so we can access it from our view and actually start writing binding expressions. So we access the view model through use of the view model providers of the app compact activity. And we provide a factory to instantiate the fact the view model if it's not already been created. You have to make sure to do this in onCreate because otherwise the activity will not have a chance to actually restore its view model store, which it retrieves from its non-configuration instance. If you're interested about how this works, I recommend checking out the source code of the app compact activity. But it's a bit messy as Android code is. So how can we prove this already? We can introduce an extension function. I love extension functions to actually retrieve the view model with a factory. You notice here that I'm using the view model new instance factory. This is a default factory that will try and actually instantiate the view model if it has no argument constructor. It's generally not safe to actually rely on this, so I would advise not using it. But it's there if you can assert that you have no arguments in your constructor. Additionally, if you want to access the property on your model later on or in another place in your activity, you can use the lazy delegate property to instantiate the view model inside and then assign that to the binding. Then you can access that later without having to worry about the nullability of your binding model. Since the generated code will have the nullable annotation, since it's technically nullable. So let's look at our view model. This is a basic implementation, a basic thing, and we have the observable field. Now, data binding provides observable fields that we can use as a kind of wrapper to notify data binding of a property change. There are a lot of primitive types, like observable Boolean, observable byte, observable char, short int, long, passable. But mostly, I want to use observable field. The observable interface allows us to add and remove listeners to notify us of a property change. And this extends the base observable by doing and implements it using the property change registry. So we can extend from this if we have a complex binding structure, and this will be important later. So as mentioned, as of 3.1, we can use lifecycle-aware components with data binding. So we can actually have our live data on our data binding as a lifecycle observer. So we'll create immutable live data, because we want to modify the value. It's still a value, but it's mutable. So it's the same as using a mutable list or just a list of. And the nice thing about this is that because mutable live data is lifecycle-aware, you have a bit more granular control over how you want to behave to notifications and changes in your data. And also provide some additional benefits that you might be aware of using transformations, switch mapping, and lifecycle owner observation. You can also use an extension function to instantiate this in a similar way that you might instantiate a mutable list of or list of or hash map of, as you would do with Kotlin. It's just the little things that make your code a little bit more readable and more concise and consistent. So let's go back to the review model, and let's introduce some asynchronous operation. They've got a service, and we fetch a list of repositories from the service, for example, GitHub. We'll just assume that there are strings, and we'll just assume that there's proper asynchronous threading going on here. It's not important. So you want to show a progress bar to the user to let them know that there's something going on in the background. So we don't have a static state, a static view, sorry. And then we want to have a progress bar disappear and appear as it's when corrected. So introduce a loading live data that we can observe. And we set the value to true and false before and after making the request. So how do we do this in our layer expressions? In our layer expression, we've got a binding to our model.loading, and we want to make sure it's visible or gone. So the problem here is we have a Boolean, which is like a two-state, whereas we want to map this to a three-state view visibility property. It's fine doing like this for now, but we can see how we can prove it in the future. So the progress bar visibility will be updated as and when this value changes because the generated data binding class will listen to the changes respectfully. We also have to import the view so that it knows to use view.visible. It's not clever enough to figure that out on its own. So what if we want to display an empty state in addition to our progress state? So say to indicate to the user that their query didn't return any results. Or we just want to have a default empty state. So we introduce a text view. But we also want to make sure this is only visible when there are no items in our model. So we have this. But we also make sure that our loading state isn't conflicting with this. So we don't want the empty to actually appear whilst our loading progress bar is a visibility. So we also combine this with the loading property. And we have a compound ternary expression here using the ampersand, which of course has to be then escaped because it's XML. And everyone loves XML. So you can already see what's going wrong here. It's too complicated. We're polluting our layout with business logic. It's not very easily testable. And it's really putting people off. It's often one of the problems that I hear from people about wanting to use data binding. Because they're worried about having complex business logic in their layouts. And it's discouraging. And it doesn't need to be. I'm really proud of this gift. Rube Goldberg machines are awesome. So how can we alleviate this? We can then create additional property in our view model so that represent the empty state. Now, it's only modifying the empty state based upon the result of the model. So it's a bit duplicitous because it's the same as what was happening in our view. But because it's happening in our view model, it means it's much more easily testable. So in our layout, we now have a bit of a cleaner expression. Now, this is better. But we're a couple of developers. We can be better than better. We can be awesome. So let's introduce binding adapters. Binding adapters allow us to create a different additional bit of specification to decide whether or not something should be bound or how it should be bound. So as I mentioned earlier, when we have a Boolean 2 state, we can then decide how to map that to a visibility 3 state, so whether to use invisible, visible, or gone. So provide additional logic. So we can create a binding adapter with gone unless property and then decide if visible, view visible, or view gone. So we've moved this conditional operator that we had in our XML layout into an actual Kotlin testable function. And furthermore, we can actually make use of Kotlin extension functions. So this is an example of an extension function available to us in the Android KTX library. So we can actually access the visibility of a view based upon whether it's visible or gone. So this is accessible both programmatically and in our declarative layouts. Unfortunately, the version in the KTX library doesn't have this annotation, but you can define your own. So now our layouts are looking much more healthy. I think it's much more clear what's going on. And we don't have to worry too much about testing, because if this is incorrect or if it's binding to the wrong property, if you say, for example, loading is actually a string instead of a boolean, then it won't compile. And we're leaning on the compiler instead of relying on unit tests. So it's much more safer and much cleaner way of doing it. Don't forget to actually use the app namespace instead of Android because we're having our own custom property. So XML looks good now, but we can improve the VM. So I'm going to go ahead and just go ahead and do a little bit of my work. Introducing bindable, also a great give. Remember how I said observable field extends from base observable? Now, this does so by actually creating a property change registry. And our bindable annotation is applied to the properties in our generated binding class, which means it generates a BR resource identifier, similar to our resource identifiers that you'll have in Android.r, and you can also access bindable resources from your code. So we can create an observable view model. An observable view model will just be a normal view model that extends from the observable interface and uses the implementation from the property change registry to let the observers know that something has changed. So we can either let it know that everything's changed or just in an individual field. So what might that look like? Sort of a simple observable view model implementation here. You can see the two methods add on property change callback and remove on property change callback will actually allow byte data binding to then listen to various properties. We've added two functions as well, where we're notifying the change and notifying the property changed. Now, it's calling the same method here, but it's referencing the different parameters. So using the parameter 0 means that all properties have changed, and you need to re-bind your entire dirty layout, or just plus an individual field to let data bind know that one field has changed, which is a little bit more concise. So in our view model, we now extend from the newly created observable view model, and we can start creating bindable properties. So instead of using mutable live data, we can create an actual implementation. So we have a variable items. So now we have a variable, which can be changed, and it's much more reflective of its mutable status. And we have the notified property change to let us know the data binding listeners that this property has changed upon set. What's really useful here as well is that the setter is private, which means we can prevent any access from outside the view model and have it really kind of localized. But it's still a little bit verbose. There's still a bit going on there. So we can remove this boilerplate. We can do better. Remember our delegate cap? We can create delegate properties again in Kotlin to define getters and setters as templates to reuse. So we can do so with an observable potty. So we can condense this getter and setter into just a property value. This is what it might look like. We want to extend the observable property in Kotlin so that we can actually listen for changes on this class so that we can react accordingly to before and after the property changes. Now, this observable property takes overrides two parameters, two functions, sorry, before change and after change. Before change takes a Boolean response. So this is to indicate whether I approve of this change or whether I'm actually allowing this change to happen. So for this, we can actually then say, I only want to change this if the old value does not equal the new value. This means that we're not unnecessarily notifying the data binding of changes. And if you're using two-way binding, it means you can actually prevent infinite loops. And if you've ever had to Google Stack Overflow on Stack Overflow, you'll know how difficult that is. It's not easy. So we've also got after change, which actually does the notification job. So it's letting the observable know that this property has changed. And you can see in our constructor that we're taking in the initial value, the observable to notify, and the identifier of the field. Now, the identifier of the field will be this property from the BR class that I mentioned earlier. Cool. So we can apply this with an extension function. I've got a lot of extension functions. You don't want to see my code. So we, those guys are laughing because they know. So we've got the annotation getBindable on our items. So make sure that this bindable annotation is applied to the getter. So that data binding know this property will change, or might change. And then we're passing in the identifier BR.items, which is generated by our data binding annotation processor. The annotation processor, by the way, does not need to be added as a capped or annotation processor in your build.gradle. It will be done so by the Android Gradle plugin. Cool. So there's a really nice article from Aiden McWilliams, actually, who demonstrates this technique and builds upon it a little bit further by using reflection to then check out the BR.items file. So it doesn't really pollute your stack trace if you have a problem at compile time. I chose not to demonstrate that here, so I recommend you please check it out. The links will be online. So awesome. We've got lots of different techniques like this that can be applied in Kotlin and data binding. And unfortunately, I can't go into great detail about them more. But I've created a sample online, which you can access on GitHub. It's all open source, and it's available on the Play Store. It's got loads of five-star reviews. By loads, I mean none. So review it, please. You can see lots of different techniques that I've used here to demonstrate how you can bind properties. So you can see the bindable property that I mentioned earlier. You can see the observable field. You can see mutable live data. And you can also see how you can use mediator live data to combine the value of two mutable live data and actually operate on a lambda on this to then have some custom behavior. You can really achieve a lot of things, and you can do so in a nice testable fashion so that your declarative layouts are nice and clean. And finally, these slides are available online in open source markdown formats because open source, all the things. So you'll be able to check out all the additional resources that I've used as well. I recommend you go check it out. There's a few blog posts on there on how to use data bind with RecyclerView. So you can actually use just one adapter. I think it was from George Mount, I think. And the aforementioned article from Ada McWilliams. So thanks. [?]. [?]. So we're running early nearly the whole day. Questions? Oh, wow. Great. Of course you have a question. Hey, thanks for the great presentation. I think like Kotlin delegated properties are great and really powerful. But something I noticed, you first used live data, but then in the Kotlin delegated property, you didn't. So can you quickly compare those two? Well, so live data will have obviously more granular control over what's happening in the lifecycle. And you can choose to use either which ever fits for your project. So you can have bindable properties because it actually represents the mutable state because it's a var instead of a val. And then you can have mutable live data as a live data. And as mentioned as well, you can use mediator live data to combine the results of other functions or do some complex internal logic if you need to. So it really is just dependent on what the needs of your projects are. OK. We have another question, right? Hi. So good presentation. I don't know, but I work for a library. And I use data binding. And I have issues because now my clients need to activate the data binding in their site. Is this how it works? Is it possible to change it? I know that the generated code is provided inside my library. But even though they need to activate data binding to make a mapper or something. I would think that because annotation processing needs to be done for this, and this is done on the top level. So unless you're actually having the generated layouts in your actual library, you probably have to definitely need it in the consuming project. I've not actually had this use case myself, so I couldn't say accurately. But I think I'm not sure there's a way around it. Any further questions? Oh, perfect. Hi. Thank you. Really great, great presentation. Thank you very much. So my question, I don't really get the part when you change the view at the flag visibility for the view. So how did you do that? Could you please repeat quickly? Thank you. So in the view model, there's a observable Boolean. And whether you use live data or a bindable property, it's not too important. But data binding will listen to this value. So normally, you wouldn't be able to directly map a Boolean to a visibility int, which would be like view dot, visible view dot, invisible. And that's the point of using a binding adapter, because in the binding adapter, you can say, I take this Boolean, and I'm turning it into the visibility int. So that's telling data binding how you want to react to this binding property. And you can use your own type for it? Absolutely. Oh, that's good. It's actually really powerful in this respect, because you can create custom views. You can create custom binding methods and binding adapters, inverse binding adapters, inverse binding methods. It's really Pandora's box. But it's massively flexible and really powerful. I've actually created a few custom views myself with inverse binding adapters. So then you can bind your custom view types from your view model in your XML layout. So it's still nice and clean. But you can have really complex logic, or as complex as your domain needs it to be. Thank you. Thank you very much. No worries. And there's one last question. Already used at the binding quite extensively. I have one question. I mean, I got one challenge with actually pushing the, some of the view model is connected to the data source. And basically, the data source is providing a list of data or collections. So the challenge is with having the collections pushed like through the stream when only one item from data source changes, but it's all the whole collection is pushed. So I still didn't find a nice solution. Like push just the item that changed at a certain position and things like that. Well, it depends on how your receivers are actually subscribing to this. So in the sample that I've got online, I'm showing a list of repositories in a RecyclerView. And now because the adapter should still be in your activity implementation, what's happening is that the view model will then expose the entire list that's changed. And that's fine. And then it will be observed in your activity. And the activity will then update the adapter. The adapter internally then has a diff util that can say only one item has changed. So it can indicate to its bound view in the RecyclerView that only this item needs to be updated. So it's a bit of an easy way of doing it. And I think if you check out the code on there, you can see how it's done. I've used a single layout adapter with a single diff util. And it will only update the fields it needs to. So you're doing the diff on the UI thread base? Yeah. OK. Thank you very much.
 So I'm Ash Davis.  I'm working with Immobilienskirts.  And I'm talking about leveraging Android data  binding with Kotlin.  Now, there's a lot of topics to get into here.  And I've only been able to cover a partial part.  But I really encourage you to check these out.  So let's start off.  What is data binding?  Data binding is a support library  that allows us to bind UI components to data sources  declaratively rather than programmatically.  It's potentially really powerful and complex,  but use effectively it can really cut down  on presentation boilerplate.  So it started off with data binding beta in 2015  when Google announced it after IO.  It's a support library that can be used right back down  to Android 2.1, which is API version 7,  to write declarative layouts and minimize the glue code required  to use application logic and layouts.  As of Android's Gradle plugin 3.1,  it includes the new data binding compiler,  so data binding version 2.  This includes incremental class generation.  So this means it will speed up your build time  a little bit, and it will have pre-compilation of classes,  which means that your data binding classes will actually  be available prior to your first build.  If you've used any annotation processes that generate classes  that you rely on at runtime, you'll  know this is an absolute pain.  So it's nice to have these even if your build buggers up.  So let's start off with a basic activity  and see how we can start using data binding with this.  This is just a basic activity how it might start off with.  So first, we want to make sure we replace the framework set  content view with that of the data binding utility  to retrieve a binding class that has been generated for us  that we can refer to in our programming code.  Also, as of the Android Gradle plugin version 3.1,  data binding is life cycle aware.  This means we need to inform the binding of our lifecycle owner  so it can manage the subscription accordingly.  So this is already pretty basic.  So how can we use Kotlin to improve this?  Let's start with the binding.  So Kotlin allows us to use delegated properties.  This business cat delegates.  So with delegate properties, we can create a getter and set  a template to define how we want to use this resource.  And we can reuse it as many times  we'd like in different places as long as it makes sense.  So for example, a delegated property  would be our Kotlin lazy delegate.  Here you can see the sample from the documentation  where computed would be referred only once.  And then the hello value would actually be referred every time  we then gone to access it.  So Kotlin gives us two interfaces  to use when we want to create our own delegate properties.  We have the read only property and the rewrite property.  These are for value properties and for variable properties  respectively.  So one is immutable and one is mutable.  And we have to implement these methods  to actually provide the functionality.  So for our delegate property for our activity binding,  we want to make sure that we're actually  using a immutable property, so the read write property.  Here we have just a basic class and want  to add our implementation to this.  So you can see that the receiver is the activity,  meaning that for this property delegate,  it has to be made from an activity  so we can use the reference activity.  We pass in the resource ID for the layout.  And we want to lazily instantiate our binding  so that we'll refer to the same one in the same way that we'd  use with lazy.  How does this look like in our activity?  So we can use an extension function  as well to access our delegate property.  This is consistent with how we do so  with a lot of other Kotlin delegate properties,  like lazy or observable, so that it looks quite nice  and consistent in our code.  So let's introduce some architecture in here  so we can actually get some business behavior.  In last year's Google I.O., Google  announced the architecture components  to start building framework applications quickly and easily.  And again, this year's Google I.O.  They announced Jetpack components  so we can get even more in there.  This includes live data and view models  and a sort of unofficial endorsement  of using model view view model as a paradigm.  So it wasn't an instruction to migrate your existing architecture  over from MVP or from MVI or for one of you  have to MVP MVVM sorry.  But it was an indication that this  is what you can use if you've got a fresh project  or if you're starting from scratch.  But data binding works really well with MVVM  because the view passively observes the view model  and it doesn't really matter if the view is there or not.  So we don't have to worry about unregistering a listener  or making sure our view is nullable or hiding all these  because we can have many or no listeners on our view model  view model properties.  And the lifecycle components react accordingly.  So the view model state is bound by view observation.  And the view model notifies the view  notifies the view model of UI events, user interactions.  I could probably talk all day about how MVVM works,  but this talk is about data binding.  So let's move on.  So this is our activity as it was before.  And we need to actually apply our model to our binding  so we can access it from our view  and actually start writing binding expressions.  So we access the view model through use of the view model  providers of the app compact activity.  And we provide a factory to instantiate the fact  the view model if it's not already been created.  You have to make sure to do this in onCreate  because otherwise the activity will not  have a chance to actually restore its view model store, which  it retrieves from its non-configuration instance.  If you're interested about how this works,  I recommend checking out the source code of the app  compact activity.  But it's a bit messy as Android code is.  So how can we prove this already?  We can introduce an extension function.  I love extension functions to actually retrieve the view  model with a factory.  You notice here that I'm using the view model  new instance factory.  This is a default factory that will try and actually  instantiate the view model if it has no argument constructor.  It's generally not safe to actually rely on this,  so I would advise not using it.  But it's there if you can assert that you have no arguments  in your constructor.  Additionally, if you want to access the property on your model  later on or in another place in your activity,  you can use the lazy delegate property  to instantiate the view model inside and then assign that  to the binding.  Then you can access that later without having  to worry about the nullability of your binding model.  Since the generated code will have the nullable annotation,  since it's technically nullable.  So let's look at our view model.  This is a basic implementation, a basic thing,  and we have the observable field.  Now, data binding provides observable fields  that we can use as a kind of wrapper  to notify data binding of a property change.  There are a lot of primitive types,  like observable Boolean, observable byte, observable char,  short int, long, passable.  But mostly, I want to use observable field.  The observable interface allows us to add and remove listeners  to notify us of a property change.  And this extends the base observable  by doing and implements it using the property change  registry.  So we can extend from this if we have a complex binding  structure, and this will be important later.  So as mentioned, as of 3.1, we can  use lifecycle-aware components with data binding.  So we can actually have our live data  on our data binding as a lifecycle observer.  So we'll create immutable live data,  because we want to modify the value.  It's still a value, but it's mutable.  So it's the same as using a mutable list or just a list of.  And the nice thing about this is that because mutable live data  is lifecycle-aware, you have a bit more granular control  over how you want to behave to notifications and changes  in your data.  And also provide some additional benefits  that you might be aware of using transformations, switch mapping,  and lifecycle owner observation.  You can also use an extension function  to instantiate this in a similar way  that you might instantiate a mutable list of or list of  or hash map of, as you would do with Kotlin.  It's just the little things that make your code a little bit more  readable and more concise and consistent.  So let's go back to the review model,  and let's introduce some asynchronous operation.  They've got a service, and we fetch a list of repositories  from the service, for example, GitHub.  We'll just assume that there are strings,  and we'll just assume that there's  proper asynchronous threading going on here.  It's not important.  So you want to show a progress bar to the user  to let them know that there's something going on in the background.  So we don't have a static state, a static view, sorry.  And then we want to have a progress bar disappear and appear  as it's when corrected.  So introduce a loading live data that we can observe.  And we set the value to true and false before and after making  the request.  So how do we do this in our layer expressions?  In our layer expression, we've got a binding to our model.loading,  and we want to make sure it's visible or gone.  So the problem here is we have a Boolean,  which is like a two-state, whereas we want to map this  to a three-state view visibility property.  It's fine doing like this for now,  but we can see how we can prove it in the future.  So the progress bar visibility will be updated as and when  this value changes because the generated data binding class  will listen to the changes respectfully.  We also have to import the view so that it knows to use  view.visible.  It's not clever enough to figure that out on its own.  So what if we want to display an empty state in addition  to our progress state?  So say to indicate to the user that their query didn't return  any results.  Or we just want to have a default empty state.  So we introduce a text view.  But we also want to make sure this is only visible when there  are no items in our model.  So we have this.  But we also make sure that our loading state isn't conflicting  with this.  So we don't want the empty to actually appear  whilst our loading progress bar is a visibility.  So we also combine this with the loading property.  And we have a compound ternary expression here  using the ampersand, which of course  has to be then escaped because it's XML.  And everyone loves XML.  So you can already see what's going wrong here.  It's too complicated.  We're polluting our layout with business logic.  It's not very easily testable.  And it's really putting people off.  It's often one of the problems that I hear from people about  wanting to use data binding.  Because they're worried about having complex business logic  in their layouts.  And it's discouraging.  And it doesn't need to be.  I'm really proud of this gift.  Rube Goldberg machines are awesome.  So how can we alleviate this?  We can then create additional property in our view model  so that represent the empty state.  Now, it's only modifying the empty state based upon the result  of the model.  So it's a bit duplicitous because it's  the same as what was happening in our view.  But because it's happening in our view model,  it means it's much more easily testable.  So in our layout, we now have a bit of a cleaner expression.  Now, this is better.  But we're a couple of developers.  We can be better than better.  We can be awesome.  So let's introduce binding adapters.  Binding adapters allow us to create  a different additional bit of specification  to decide whether or not something should be bound  or how it should be bound.  So as I mentioned earlier, when we have a Boolean 2 state,  we can then decide how to map that to a visibility 3 state,  so whether to use invisible, visible, or gone.  So provide additional logic.  So we can create a binding adapter with gone unless property  and then decide if visible, view visible, or view gone.  So we've moved this conditional operator  that we had in our XML layout into an actual Kotlin testable  function.  And furthermore, we can actually make use  of Kotlin extension functions.  So this is an example of an extension function available  to us in the Android KTX library.  So we can actually access the visibility of a view  based upon whether it's visible or gone.  So this is accessible both programmatically  and in our declarative layouts.  Unfortunately, the version in the KTX library  doesn't have this annotation, but you can define your own.  So now our layouts are looking much more healthy.  I think it's much more clear what's going on.  And we don't have to worry too much about testing,  because if this is incorrect or if it's  binding to the wrong property, if you say, for example,  loading is actually a string instead of a boolean,  then it won't compile.  And we're leaning on the compiler instead  of relying on unit tests.  So it's much more safer and much cleaner way of doing it.  Don't forget to actually use the app namespace instead of Android  because we're having our own custom property.  So XML looks good now, but we can improve the VM.  So I'm going to go ahead and just  go ahead and do a little bit of my work.  Introducing bindable, also a great give.  Remember how I said observable field extends from base  observable?  Now, this does so by actually creating a property change  registry.  And our bindable annotation is applied to the properties  in our generated binding class, which  means it generates a BR resource identifier, similar  to our resource identifiers that you'll have in Android.r,  and you can also access bindable resources from your code.  So we can create an observable view model.  An observable view model will just  be a normal view model that extends from the observable  interface and uses the implementation  from the property change registry  to let the observers know that something has changed.  So we can either let it know that everything's  changed or just in an individual field.  So what might that look like?  Sort of a simple observable view model implementation here.  You can see the two methods add on property change callback  and remove on property change callback  will actually allow byte data binding to then listen  to various properties.  We've added two functions as well,  where we're notifying the change and notifying  the property changed.  Now, it's calling the same method here,  but it's referencing the different parameters.  So using the parameter 0 means that all properties have  changed, and you need to re-bind your entire dirty layout,  or just plus an individual field to let data bind know  that one field has changed, which  is a little bit more concise.  So in our view model, we now extend  from the newly created observable view model,  and we can start creating bindable properties.  So instead of using mutable live data,  we can create an actual implementation.  So we have a variable items.  So now we have a variable, which can be changed,  and it's much more reflective of its mutable status.  And we have the notified property change  to let us know the data binding listeners  that this property has changed upon set.  What's really useful here as well is that the setter is  private, which means we can prevent any access from outside  the view model and have it really kind of localized.  But it's still a little bit verbose.  There's still a bit going on there.  So we can remove this boilerplate.  We can do better.  Remember our delegate cap?  We can create delegate properties again in Kotlin  to define getters and setters as templates to reuse.  So we can do so with an observable potty.  So we can condense this getter and setter  into just a property value.  This is what it might look like.  We want to extend the observable property in Kotlin  so that we can actually listen for changes on this class  so that we can react accordingly to before and after the property  changes.  Now, this observable property takes overrides two parameters,  two functions, sorry, before change and after change.  Before change takes a Boolean response.  So this is to indicate whether I approve of this change  or whether I'm actually allowing this change to happen.  So for this, we can actually then say,  I only want to change this if the old value does not  equal the new value.  This means that we're not unnecessarily  notifying the data binding of changes.  And if you're using two-way binding,  it means you can actually prevent infinite loops.  And if you've ever had to Google Stack Overflow on Stack  Overflow, you'll know how difficult that is.  It's not easy.  So we've also got after change, which actually  does the notification job.  So it's letting the observable know  that this property has changed.  And you can see in our constructor  that we're taking in the initial value, the observable  to notify, and the identifier of the field.  Now, the identifier of the field will  be this property from the BR class that I mentioned earlier.  Cool.  So we can apply this with an extension function.  I've got a lot of extension functions.  You don't want to see my code.  So we, those guys are laughing because they know.  So we've got the annotation getBindable on our items.  So make sure that this bindable annotation is applied  to the getter.  So that data binding know this property will change,  or might change.  And then we're passing in the identifier BR.items, which  is generated by our data binding annotation processor.  The annotation processor, by the way,  does not need to be added as a capped or annotation processor  in your build.gradle.  It will be done so by the Android Gradle plugin.  Cool.  So there's a really nice article from Aiden McWilliams,  actually, who demonstrates this technique  and builds upon it a little bit further  by using reflection to then check out the BR.items file.  So it doesn't really pollute your stack trace  if you have a problem at compile time.  I chose not to demonstrate that here,  so I recommend you please check it out.  The links will be online.  So awesome.  We've got lots of different techniques like this that  can be applied in Kotlin and data binding.  And unfortunately, I can't go into great detail about them  more.  But I've created a sample online,  which you can access on GitHub.  It's all open source, and it's available on the Play Store.  It's got loads of five-star reviews.  By loads, I mean none.  So review it, please.  You can see lots of different techniques  that I've used here to demonstrate  how you can bind properties.  So you can see the bindable property that I mentioned  earlier.  You can see the observable field.  You can see mutable live data.  And you can also see how you can use mediator live data  to combine the value of two mutable live  data and actually operate on a lambda on this  to then have some custom behavior.  You can really achieve a lot of things,  and you can do so in a nice testable fashion  so that your declarative layouts are nice and clean.  And finally, these slides are available online in open source  markdown formats because open source, all the things.  So you'll be able to check out all the additional resources  that I've used as well.  I recommend you go check it out.  There's a few blog posts on there  on how to use data bind with RecyclerView.  So you can actually use just one adapter.  I think it was from George Mount, I think.  And the aforementioned article from Ada McWilliams.  So thanks.  [?].  [?].  So we're running early nearly the whole day.  Questions?  Oh, wow.  Great.  Of course you have a question.  Hey, thanks for the great presentation.  I think like Kotlin delegated properties are great and really  powerful.  But something I noticed, you first used live data,  but then in the Kotlin delegated property, you didn't.  So can you quickly compare those two?  Well, so live data will have obviously  more granular control over what's happening in the lifecycle.  And you can choose to use either which ever  fits for your project.  So you can have bindable properties  because it actually represents the mutable state  because it's a var instead of a val.  And then you can have mutable live data as a live data.  And as mentioned as well, you can use mediator live data  to combine the results of other functions  or do some complex internal logic if you need to.  So it really is just dependent on what  the needs of your projects are.  OK.  We have another question, right?  Hi.  So good presentation.  I don't know, but I work for a library.  And I use data binding.  And I have issues because now my clients  need to activate the data binding in their site.  Is this how it works?  Is it possible to change it?  I know that the generated code is provided inside my library.  But even though they need to activate data binding  to make a mapper or something.  I would think that because annotation processing  needs to be done for this, and this is done on the top level.  So unless you're actually having the generated layouts  in your actual library, you probably  have to definitely need it in the consuming project.  I've not actually had this use case myself,  so I couldn't say accurately.  But I think I'm not sure there's a way around it.  Any further questions?  Oh, perfect.  Hi.  Thank you.  Really great, great presentation.  Thank you very much.  So my question, I don't really get the part  when you change the view at the flag visibility for the view.  So how did you do that?  Could you please repeat quickly?  Thank you.  So in the view model, there's a observable Boolean.  And whether you use live data or a bindable property,  it's not too important.  But data binding will listen to this value.  So normally, you wouldn't be able to directly map a Boolean  to a visibility int, which would be like view dot,  visible view dot, invisible.  And that's the point of using a binding adapter,  because in the binding adapter, you can say,  I take this Boolean, and I'm turning it  into the visibility int.  So that's telling data binding how you want to react  to this binding property.  And you can use your own type for it?  Absolutely.  Oh, that's good.  It's actually really powerful in this respect,  because you can create custom views.  You can create custom binding methods and binding adapters,  inverse binding adapters, inverse binding methods.  It's really Pandora's box.  But it's massively flexible and really powerful.  I've actually created a few custom views myself  with inverse binding adapters.  So then you can bind your custom view types  from your view model in your XML layout.  So it's still nice and clean.  But you can have really complex logic,  or as complex as your domain needs it to be.  Thank you.  Thank you very much.  No worries.  And there's one last question.  Already used at the binding quite extensively.  I have one question.  I mean, I got one challenge with actually pushing the,  some of the view model is connected to the data source.  And basically, the data source is providing a list  of data or collections.  So the challenge is with having the collections pushed  like through the stream when only one item from data source  changes, but it's all the whole collection is pushed.  So I still didn't find a nice solution.  Like push just the item that changed at a certain position  and things like that.  Well, it depends on how your receivers are actually  subscribing to this.  So in the sample that I've got online,  I'm showing a list of repositories in a RecyclerView.  And now because the adapter should still  be in your activity implementation, what's  happening is that the view model will then  expose the entire list that's changed.  And that's fine.  And then it will be observed in your activity.  And the activity will then update the adapter.  The adapter internally then has a diff util that can say only  one item has changed.  So it can indicate to its bound view in the RecyclerView  that only this item needs to be updated.  So it's a bit of an easy way of doing it.  And I think if you check out the code on there,  you can see how it's done.  I've used a single layout adapter with a single diff util.  And it will only update the fields it needs to.  So you're doing the diff on the UI thread base?  Yeah.  OK.  Thank you very much.
_DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_0_419.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_420_1451.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_1452_1559.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_1560_1991.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_1992_3035.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_3036_3503.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_3504_4595.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_4596_7271.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_7272_11375.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_11376_11447.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_11448_11495.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_11496_11543.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_11544_11591.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_11592_13955.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_13956_15983.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_15984_17219.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_17220_17495.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_17496_18023.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_18024_20015.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_20016_20111.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_20112_20171.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_20172_20423.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_20424_20483.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_20484_20735.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_20736_20795.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_20796_23399.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_23400_23843.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_23844_25643.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_25644_27215.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_27216_28463.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_28464_36323.png _DCBerlin18_104_Davies_LEVERAGING_ANDROID_DATABIND_Bl9DatA1RAk_36324_36738.png