Descent into Data Binding

The new Android data binding library is capable of many things: extracting views into fields, wiring up callbacks, even evaluating simple expressions. How deep do you want to go? If you have not yet dipped your toes into data binding, this 360|AnDev talk will be a thorough introduction intended to get you familiar and confident with the tool in a practical way.


Introduction (0:00)

My name is Bill Phillips and I work for Big Nerd Ranch. We train and we write apps. If that name rings a bell, maybe it’s because you saw it on the cover of the book titled Big Nerd Ranch Guide to Android Programming. I work on this, but I also write code and I teach classes. If you or your company need to teach a bunch of people Android or iOS or front-end development, or if you happen to need some hired guns to write apps, think about Big Nerd Ranch. That’s what we do.

I have three goals in this talk:

  • The first one is, I want to show you guys how to use data binding and I don’t mean show a bunch of code snippets. I want to show you how to go through the IDE, from a project that doesn’t have data binding in it, and integrate it into this project.
  • The next thing that I want to do is take an opportunity to look under the hood and hopefully de-mystify the data binding process for you guys. When I first got into data binding, I was a little suspicious of a bunch of magic going on underneath the hood. We’re not going to look at all of that, but we’ll look at enough of that that hopefully at the end of this talk you’ll have an idea of what’s going on.
  • Finally, the last thing I want to talk about is what destinations I might have in integrating data binding into my own code base. Whenever we’re integrating a new tool, especially one that can do as much as data binding, we often at times in a professional context ask ourselves, “How much am I going to use this?” I’m going to advocate a couple of different options for you on how much you can integrate this into your project.

Data binding (2:41)

Now I want to start by talking about what this project is. This is an app called “Criminal Intent,” which if you’re familiar with our book than you’re probably familiar with Criminal Intent. It’s the same app that is in the book. I’ve modified it in a couple of minor ways to fit with presenting data binding. But if I look in my emulator I can see that Criminal Intent is a little app that is meant to log workplace crimes.

I’ve got a whole bunch of automatically generated crimes here. If I click on one then it’s going to pull up a detail for that individual crime. For this presentation, I am not going to integrate data binding into the entire thing. Instead we’re going to focus on this screen, the list activity.

If I look at my source code, I can see that CrimeListActivity is represented right here and this is really just a thin wrapper around CrimeListFragment. If I open up CrimeListFragment I would see that this has the meat of my implementation.

I have my recycler view here. It’s getting set up in onCreateView. If I scroll down to this updateUI method I see it’s setting up an adapter and then CrimeAdapter. If I jump to that declaration I can see that is using a tool, CrimeHolder. CrimeHolder is using this list_item_crime.

I’ll look at CrimeHolder. It’s not too exciting, I’ve got three views that I’m interested in there: the title, the date, and a solved checkbox. I pull them out and every time I bind to a new crime, I set up those views with the new information. The actual layout file looks like this. Again, nothing too exciting going on here. I’ve got a relative layout with three children in there, and the details of how those are related to one another are not super important for the context of this discussion. That’s the basic architecture that we’re dealing with.

What I’d like to do is start working with data binding in this project. The first thing I need to do is have my tools up to date. I do have an up-to-date version of Android Studio. Inside of my main project level build.gradle, I have my Gradle tools up to the most recent version for this version of Android Studio as well. You want to make sure you have that before you even start.

On this specific project, to enable data binding it is really important to enable two parts. One part of data binding is this part that’s going to rip through our layout files and automatically generate Java classes. There’s a part of data binding that’s integrating with the build process here, so that’s one reason I need to modify my build.gradle. The other reason is that there’s a part of data binding that is integrated to the IDE as well.

Get more development news like this

What I do inside of my build.gradle, is I say:


data binding {
	enabled = true
}

Then I go ahead and re-sync my Gradle. When I do that it’s turning on both of those. It’s saying, “Okay, turn on the IDE integration. Turn on the build integration.”

The next thing I need to do to integrate data binding is I need to go into my resources, into the layout file that I want to enable data binding on. list_item_crime was what we were working with earlier, so I’ll crack that open. What I need to do is wrap this entire XML layout file in a tag called layout. I type out layout and I’ll wrap this in here. Note that I don’t even need to move over my XML name space declarations. This will work just fine.

I have seen sometimes if I go directly through this route that for my next step I have to start and restart Android Studio. Now by doing that, by wrapping my layout file, and turning on data binding, I’ve automatically triggered the generation of a binding class. That binding class is named after my XML file. It’s just camel-cased instead, so list_item_crime turns into ListItemCrimeBinding in my Java code.

What I’m going to do is go into CrimeListFragment, into my adapter here. And where previously I was inflating that layout file, what I’m going to do instead is I’m going to call DataBindingUtil.inflate and I pass in my layoutInflater and import that class. I pass in the layout file I want to inflate, the parent, and then false. It did generate that class for me.


DataBindingUtil.inflate(layoutInflater, R.layout.list_item_crime, parent, false);

There’s ListItemCrimeBinding, and I’ll name that Binding, and I’ll assign the result of that DataBindingUtil.inflate() call to that binding object.

Now usually that binding object is going to be used in the same place where I was writing my code in my holder object that I defined. You know how my holder had the views pulled out and I was assigning things to it? That’s kind of the realm that my binding object is working in. I’m going to take that binding object and pass it into my CrimeHolder object. Then I’ll navigate over to my CrimeHolder, and change this to ListItemCrimeBinding binding and I’ll do this handy option return shortcut to create a field for that and assign it.

Now I’ve got my binding. What can I do with it? The first thing I need to do is my super constructor still needs to get the view. How do I get it? The most basic thing that it does is it has a reference to the view hierarchy it inflated. Inside my binding I can say binding.getRoot, and that will yield the view that was inflated underneath that. More interesting is that when I inflate using data binding, it’ll automatically rip through my layout file and look at every view that has an ID on it, create a field for that view, and assign it to it. Without me doing anything else.

I can write here, since I already have that in the binding field, mbinding, and you can see that I’ve got fields for titleTextView, dateTextView, and solvedCheckBox. I can immediately substitute out all this code I had for my binding code. Then I can just nuke all this code here. That’s one cool trick that I get immediately, as soon as I wrap it in that layout tag.

Another thing that I can do, as soon as I wrap it in that layout tag, is inside the layout file itself I get to use something I call the Binding Mustache Operator ({}). What is that operator? I’ve got this field here, padding that I’ve defined as, @dimen_list_item_padding_2x. If you go look inside this you can see that all I’ve really done is defined a dimension that is twice the size of another dimension. Now because of the way that my resource system works, if I want to have something that’s twice the size of another I pretty much have to define another item there or do it in my Java code.

But what I can do with the Binding Mustache Operator is, I can actually use simple Java expressions here. What I can do is instead of saying 2x, I could multiply that list item padding by two. And it works great.

These are the two things that I get with this simple kind of data binding, with this layout tag on the outside, and these simple usages of this Binding Mustache Operator.

Now remember, there is a code generation part of this, but there is also an IDE integration part of this. When I auto-complete on mbinding, I get a bunch of Java methods. These have been generated by the data binding framework for me, so there is somewhere sitting out there a Java class that has this code written in it.

Now where things get interesting is in the IDE integration. If I right click on mCrime and say, Go To, Declaration it’s going to take me to where I had that field declared. What do you think is going to happen when I right-click on this? You would think the same thing, right? Go To, Declaration. It does not take me to the generated code, though. It takes me to where I effectively did declare it. Effectively, I declared it in my XML File when I wrote that ID, inside of a data binding context. That’s the IDE integration at work. It is a little confusing the first time you see it because you think, “Hey, this is a field. This should take me to a field.” But in practice when we start working with this, this ends up being really handy.

This is my first stopping off point. I mentioned at the beginning that I had a couple of different destinations that I was interested in taking you guys. This is one of them. This is what I call Step Zero data binding. And by that I mean that all I’ve done is wrapped my layout file in this layout tag and I’ve used it in my code. I automatically get view extraction. I get these simple uses of the Binding Mustache Operator if I want to use those as well, and I didn’t really have to invest much into this.

I’m a big fan of this and the nice thing about this level of commitment to the tool is that it doesn’t really impose anything on you architecturally in your application. You can pretty much build your apps the same way you did before, and use this as a nicer version of, say, something like Butter Knife. This has got fewer steps involved. If I add a view in here, I can immediately start using the field in my code. I’m a big fan of that.

Digging deeper into data binding (14:59)

Let’s get a little deeper into this. Things get a little more interesting in data binding with the next section I’m going to introduce here. I’ve got the top level layout tag, but I can also define a data section here.

In the data section I can define values that I want to pass into the layout file. The values that I’m really interested in within my existing code are all this stuff referring to crime. I can define a variable, named crime, in my layout file that has that same type. That defines a variable named crime. At the same time I define that inside of CrimeListFragment, I would see that my binding object gets an additional method. I have a getter and a setter for crime now. I’m going to set the crime on my layout file every single time that I bind to this view holder.

Now that I’ve done that, I can refer to that variable within my layout file in my Binding Mustache context. Where would that be useful? Here in my checkbox I could say checked is equal to @-Binding-Mustache-Crime.isSolved. I just call the ifSolved method. And that gets populated directly from the crime that I pass in. Same thing goes for my title, I say text, Crime.getTitle, and the same thing goes for my date. Crime.getDate.toString. Since that is returning a date object I want to make sure to convert it to string.

Again, I can use simple Java expressions. What if I want a fancier date here? Let’s say that I want to say that the date that this crime was discovered was such and such. I could type out with double quotes like I would in Java. But I would have to escape it inside of my XML here, so that’s kind of annoying. Data binding allows me to instead use a back tick to do this, so I can say date discovered, plus, and I build up my screen that way. Pretty handy.

Now some of you may be looking at this, if you know you’re Android very well, and thinking to yourselves, “Bill, I can’t localize this string. What are you doing?” I can use my string values here too so, I happen to have defined, before the lecture, another string. I can say @string/list_item_date_format. The syntax on this is a little different. It acts like a function. I pass in the value that I want to format and that should work great.

Now one other additional thing that I can do here is I can set up click listeners. I don’t know if you recall, but in my CrimeListFragment my CrimeHolder was handling these click events. I set this on click listener to this on the top level item view and then I handled the click inside of onClick. Well if I want to, I can pass that end directly, I can make another variable for the holder, and complete that out again, CrimeListFragment.CrimeHolder. Then, on my relative layout up top I can say onClick, and I can use a little Lambda expression. I know that my on click list takes in a view and yields nothing so I can say view and then holder.onClick(view). I also want to say mbinding.setHolder(this). Now I can cut out even more code here.

The difference is that I’ve got all of that code wired up inside of my layout file instead. There is something that’s a little wrong here though. Let’s see if anybody’s got sharp eyes. I’m going to scroll through this. Yell out if you see anything funny. What’s going on with the checkboxes? They’re kind of animating into place or something. That’s kind of weird. Let’s dive in a little bit and see what’s going on with that. Why would that be happening?

Remember this is a generated code library, so that means that when I inside of my CrimeHolder call setCrime, that is running some Java code behind the scenes that is triggering everything that I see on this screen. If I command-B into that, it’s going to just send me to that variable. Which normally is what I want, but right now I don’t exactly know what’s going on.

Now, normally because of the IDE integration, it will not always generate that code for me. It’s doing some magic behind the scenes so that we can have a seamless editing experience without waiting for those compile cycles to happen. Since I ran it and deployed it to the device, I do get the generated code. All I had to do is switch over in my IDE view to look behind what’s going on. Now my Android view isn’t going to show that to me so I’m going to switch to the project view.

Inside the project view I’m going to crack open build, and it’s not in the generated code, it is in the intermediates section. Under intermediates I have classes, debug and then I’m going to dive down into comm, bignerdranch, androidcriminalintent, and then there’s databinding. So it generates those classes in a sub-package in there called databinding. If I crack that open, sure enough, there I see ListItemCrimeBinding.

If I double-click that I see some pretty well-formatted code considering it was generated, but it’s not super-duper readable. Let’s look in here for that setCrime setter to see what’s going on. I want the definition. So here setCrime is taking in my crime, and it’s assigning it to an ivar and it’s marking some dirty flags calling this notified property changed method, and then calling this request re-bind. Let’s look at this request re-bind in the super class.

Inside here it’s checking to see if it has a pending re-bind, and if it is, it’s flagging that. If it is flagging that there is a pending re-bind, it posts this callback. This may or may not mean anything to you. The important thing to note about this is that since it is posting a callback to either a choreographer or a handler, that means that it is not immediately running this code. It is running it one tick later. If I were in my CrimeDetailActivity that wasn’t scrolling or anything, I wouldn’t care about that. But that one-tick delay is what’s causing that little animation to play.

What we want to do is we want to get rid of that tick. What we’re going to do is back inside of ListCrimeFragment we want to say right after we say setCrime, execute these bindings immediately. Do not wait. We are not going to make any additional changes to the layout. You can go ahead and run this. We do this by calling a method on binding called executePendingBindings. All that does is immediately run this method on the binding generated class called ExecuteBindings. That takes care of the work of taking all my values from crime, running all of my expressions and my Binding Mustaches, and assigning them.

Let’s go back to our layout. When I showed you how to use variables here I was showing in a lot of ways the simpler way of doing things, or the more Java-y way of doing things. Data binding has some additional syntactic sugar that can make this stuff a little easier for us. One example would be this crime.getDate().toString(). Let’s say that I, for some reason, decided to end my crime and getDate, just return null. Maybe there was a bug somewhere, who knows. Data binding does some automatic null-handling for me.

When I have an expression, like this, it actually has a behavior that it relies on when it’s trying to call a method on a null value. For example, here getDate is null, but when I call toString on it, instead of throwing a null pointer exception, what it’ll do is just say, “Well, if I’m calling a method that returns an object on a null object, I’ll just make the whole expression return a null object.” This is convenient for our view related code where we may not have the space in here to do all of the error handling that I might want to do to make it perfect.

Another thing that I can do in data binding is I don’t have to type out everything. getDate is a property notation, and in data binding I can abbreviate that to just date. It works exactly the same. Same thing goes for my title. It respects the isSolved too, so I can say Crime.solved and that also works. Another thing that I get inside data binding is I have a null coalescing operator. Let’s say that I decide that maybe null isn’t something that the user wants to look at on this screen. I could inside here say ?? and say Never instead. Then, when my date is null and when my string is null, it will yield never instead of null which is maybe something a user might prefer to look at.

Let’s start playing around again with how things work. This Binding Mustache Operator. I want to talk a bit more about how this works. Let’s say that I decided for some reason to write android:allCaps and use a Binding Mustache Operator to assign that to true. I can go inside here and rebuild my project and this will work fine. This will compile. If I ran it, it would work great. I would see all caps in my application. But if I remove that Binding Mustache Operator here, in this specific case I’ve chosen this all caps attribute, somewhat deviously. In this specific case, when I rebuild the project it’ll error out on me. It says “No resource identifier found for attribute allCaps in package Android”. I, of course, am saying “Oh, duh, I must’ve gotten it wrong.” It’s actually text all caps, right? So I rebuild it. And run again. And, I get the exact same error. That’s kind of weird.

If I look closely at what’s going on, I’ll see some weird things. Like where did that tag come from? And if I scroll up here, I’ll see that I don’t actually have a data section here. The reason for that is that, unlike other code generation libraries, data binding is generating two things. It is generating the Java classes, but is also generating modified versions of the layout files that I pass in. The reason it does that is because the Binding Mustache Operator does not use the same inflation mechanism that the XML layout does. I would go fix this by going back to my source here and saying textAllCaps.

But that brings up the other question. Why did all caps here work when I had the Binding Mustache? The reason this works is that the default behavior of data binding is to set properties on the views that I’m looking at. If I were to go inside my documentation for text view I would find that it has a property called allCaps and a method called setAllCaps. What’s happening when I use the Binding Mustache here is it is looking at that and saying, “Oh, that must be referring to that property. I’ll go and assign that.” That’s what it’s generated code is doing. If I were to look inside of this file, I would see, and I’m not going to see that here because I didn’t do a rebuild to re-generate this, I would see that that allCaps attribute would be gone because it’s going to be handled by the data binding processor instead.

This gets a little interesting when I ask myself questions like, things that I think I should be able to do in data binding but I don’t know exactly how it would work. What do I mean by that? Let’s say that I, inside of my CrimeHolder, wanted to add a text watcher to my titleTextView and addTextChangeListener. Text watcher is a listener interface that is different from the on-click interface that I used earlier. The on-click interface only had one method, which means that I can use a Lambda expression for it. But text watcher does not. It has three methods on it. How can I use data binding with this?

This gets into what are called binding adapters. Data binding has some extra helper classes that are on board to make it possible to do something like this. I can open up the binding adapters that ship with data binding and take a look at them. What I can do is say Command-O for “open class,” and I can say “text view.” You see that TextViewBindingAdapter class there? Let’s open that up. This is a text view binding adapter. The reason it’s called a binding adapter is it’s meant to adapt fields or properties or methods that you would want to use in a data binding context to that data binding context.

At the top of a lot of binding adapters you’ll see these kind of annotations up here. These are where you’ll find things like that textAllCaps one that we ran into. These are used for simple aliases. Here this attribute is saying textAllCaps is referring to the method setAllCaps. Now I can use it like I would a normal layout file.

This kind of alias thing isn’t going to work for text watcher though. I’m going to scroll down, and let’s look for text watcher and see if there’s something in there that I can use. Sure enough, there’s a setTextWatcher method and an app binding adapter annotation on top of it. This setTextWatcher method takes in a text view that I’m processing in data binding. Then, a set of parameters, for each parameter I take in, there is a corresponding attribute up here. I can see how I got attributes beforeTextChange, onTextChanged and afterTextChanged, and corresponding interfaces for those three attributes.

What are those interfaces? If I navigate to that declaration I can see that all that they’ve really done is split up that text watcher interface into three separate interfaces. Now I’ve got interfaces that I can use inside of a Lambda expression, or otherwise.

What goes on inside here isn’t of a whole lot of interest. It basically takes those three interfaces that come in and puts them together into a single text watcher that it can add onto this text view. If you find yourself in this circumstance of, I got some view that I don’t know how to use data binding with, check out the binding adapters. They may very well have what you need in them.

Integration (35:27)

I’ve gone a very long time and I have not talked about another destination. I was talking about this Step Zero data binding earlier. The last destination I want to talk about is something I don’t have time to go into great depth on, but is what I’m going to recommend as your next destination in integration, if you choose to pick up data binding. That is, model-view-view-model (MVVM).

Let’s look at our layout file again. From a standpoint of maintainability I have an issue here. The concern that we want to address is the issue of having too much code in our data binding. It’s not easy to create an instance of this and put it under a unit test that’s full of all these views and stuff. We would really rather have a pure Java class to test instead. As long as I have both crime and holder in here, anything in the relationship between crime and holder is going to show up in code in my data binding file.

What I recommend doing is instead, creating a separate class, called a view model, to hold this. I’m going to create CrimeViewModel and it will need in order to run the click listeners an activity because it’ll need to fire an intent. I’ll create a field for that and it’s going to need a Crime also.

Then on my view model what I do is I expose, directly, the values that I want to put inside of my layout file. For example, I’d have a method, getTitle and I’d return mCrime.getTitle. Same thing goes for rendered date getRenderedDate. I’m going to have to do my null checking by hand here, unfortunately. It’s not able to null. I will have just one view model. I neglected to add one thing. I do also need to have the click handler here, onCrimeClicked. I’ll say:


public void onCrimeClicked() {

	CrimePagerActivity.newIntent(mActivity, mCrime.getId()
	mActivity.startActivity(intent);
}

Then I wire that up here, viewModel.onCrimeClicked. Then I substitute view model elsewhere.

The advantage to doing it this way is in the long run, in maintainability. Right now, the payoff doesn’t look that great. I’m just calling directly through to another method. I need to have getters and setters for Crime, and inside of List Fragments I need to set view model CrimeViewModel(getActivity), assign that to a field in view model, and then I say mViewModel.setCrime. Now we should be good to go.

Now the downside of doing things this way is that it’ll appear to run initially, appear to look great, but when I scroll down you’ll notice that it doesn’t repopulate those. The reason why is look how, inside my bindCrime, I am triggering that. I’m saying ViewModel.setCrime but when I dive into that, there’s nothing there to trigger any binding code.

What we do to solve this is we change this so that it instead extends this observable class, base observable. This is another tool that comes with data binding. When I have an observable class, what I can do is, I can mark specific getters as bindable. That is advertising to the binding framework that these specific properties are available to be bound. Then, more importantly, when I call setCrime, I can call this method notifyChange. What that will do, is it will signify to data binding that all of my bindable properties have changed.

This time when I run it they should all get populated correctly. That takes me to the end of everything that I had.

Conclusion (42:33)

The things I didn’t have time for in this presentation: One, there’s so much more to say about model-view-view-model (MVVM) architecture. There’s plenty of blog posts out there to talk about it. I recommend going and checking that out if you’re interested in data binding.

Includes. This is where we have data binding within our data binding. It turns out this is really handy in practice. I was kind of skeptical of it, but it really becomes invaluable. It allows me to compose binding layouts together.

Finally, two-way data binding. That’s where I am able to send stuff to and receive stuff from, i.e., an editable text view or something like that.

My things to remember: if you enjoyed this talk and want to take something home, take home no data section. That’s a totally legitimate approach. You can absolutely do that. Number two, Mister Binding Mustache. He eats the XML attributes. He spits out Java property setters and BindingAdapter invocations. He is a different way of going through this layout process. And finally, use view models if you are going to dive head first into this stuff. We’ve been really happy with it at Big Nerd Ranch in our consulting work. It’s really paid off for us. That’s it. Thank you very much.

Bill Phillips

Bill Phillips, a Fellow at Big Nerd Ranch, is coauthor of the best-selling Big Nerd Ranch Guide To Android Programming, now in its second edition. He has been writing Android applications and teaching Android fundamentals at Big Nerd Ranch for five years.

Transcribed by Hilary Fosdal
Edited by Curtis Chen