Data binding is a process that establishes a connection between an application's UI and its business logic so that when data changes, it is reflected in the UI and vice versa. Android introduced data binding in 2015 to minimize glue code between layouts and logic. The key steps to using data binding are: 1) adding the data binding library, 2) applying binding to layouts, 3) creating data binding objects, and 4) doing the binding in activities/fragments. Data binding supports observable objects to automatically update views when data changes. It allows binding layout properties like visibility and text fields.
2. 20 yrs tinkering with computers
A lot of time on software localization
On Android since 2010 (Cupcake)
Mobile R+D Lead at Worldine Iberia
Android GDE (Google Developer Expert)
I love making UI
Proud parent of a 8 years old OS fan
@sergiandreplace
sergiandreplace.com
sergi.Martinez[at]gmail.com
About me – Sergi Martínez
3. Android data binding
Introduced by Google in I/O 2015 (almost unnoticed)
But really important. It will change the way we make UIs
4. Google dixit
Writing declarative layouts and minimize the
glue code necessary to bind your application
logic and layouts.
Data Binding library is for...
5. What is data binding?
Data binding is the process that establishes a
connection between the application UI (User
Interface) and Business logic. If the settings and
notifications are correctly set, the data reflects
changes when made. It can also mean that when
the UI is changed, the underlying data will reflect
that change
Wikipedia – Data binding
8. z
Inflation process
Inflate as
Or also performed inside setContentView
LayoutInflater.from(this).inflate(R.layout.activity_main, rootView);
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
9. Steps on inflation
1. The inflater parses the xml file
2. The inflater tries to create an object as:
a. android.widget.<tag>
b. android.webkit.<tag>
c. <tag>
3. If succeds: creates the objects and sets the right
properties
If fails: hell on earth
10. z
Some code (using custom inflater)
New inflater defined as InflaterFactory
11. z
Some code (using custom inflater)
New inflater defined as InflaterFactory
12. z
Some code (using custom inflater)
Once we set a new InflatorFactory, we are ready for inflation
18. The whole example
Check it out on
https://github.com/sergiandreplace/AndroidFontInflaterFactory
(old Eclipse structure)
Also an experiment, use at your own risk
26. z
Apply binding to layout
Before
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:text="@string/hello_world" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
27. z
Apply binding to layout
After
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="data"
type="com.sergiandreplace.hellodatabinding.ViewData" />
</data>
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=“@{data.helloMessage}" />
</RelativeLayout>
</layout>
28. z
Apply binding to layout
New root tag <layout>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="data"
type="com.sergiandreplace.hellodatabinding.ViewData" />
</data>
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=“@{data.helloMessage}" />
</RelativeLayout>
</layout>
29. z
Apply binding to layout
Two parts: data and layout itself
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="data"
type="com.sergiandreplace.hellodatabinding.ViewData" />
</data>
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=“@{data.helloMessage}" />
</RelativeLayout>
</layout>
30. z
Apply binding to layout
Name of object to be injected and type of the object
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="data"
type="com.sergiandreplace.hellodatabinding.ViewData" />
</data>
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=“@{data.helloMessage}" />
</RelativeLayout>
</layout>
31. z
Apply binding to layout
Binded property of the object
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="data"
type="com.sergiandreplace.hellodatabinding.ViewData" />
</data>
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=“@{data.helloMessage}" />
</RelativeLayout>
</layout>
32. z
Create data binding object
This way:
Or this way:
public class ViewData {
public final String helloMessage;
public ViewData(String helloMessage) {
this.helloMessage = helloMessage;
}
}
public class ViewData {
private final String helloMessage;
public ViewData(String helloMessage) {
this.helloMessage = helloMessage;
}
public String getHelloMessage() {
return helloMessage;
}
}
33. z
Create data binding object
This way:
Or this way:
public class ViewData {
public final String helloMessage;
public ViewData(String helloMessage) {
this.helloMessage = helloMessage;
}
}
public class ViewData {
private final String helloMessage;
public ViewData(String helloMessage) {
this.helloMessage = helloMessage;
}
public String getHelloMessage() {
return helloMessage;
}
}
34. z
Create data binding object
This way:
Or this way:
public class ViewData {
public final String helloMessage;
public ViewData(String helloMessage) {
this.helloMessage = helloMessage;
}
}
public class ViewData {
private final String helloMessage;
public ViewData(String helloMessage) {
this.helloMessage = helloMessage;
}
public String getHelloMessage() {
return helloMessage;
}
}
35. z
Do the binding
On the activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ViewData data = new ViewData(getString(R.string.hello_world));
binding.setData(data);
}
36. z
Do the binding
On the activity
We create the binding object
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ViewData data = new ViewData(getString(R.string.hello_world));
binding.setData(data);
}
37. z
Do the binding
On the activity
Layout name Proper cased + Binding (activity_main.xml -> ActivityMainBinding)
Generated on compilation. You must launch make before AS can recognize
Only worked with canary (1.4 RC3)
1.4 published yesterday (it should work)
You must use Java 1.7 as language level
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ViewData data = new ViewData(getString(R.string.hello_world));
binding.setData(data);
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
38. z
Do the binding
On the activity
Instantiate our ViewData object and set a message
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ViewData data = new ViewData(getString(R.string.hello_world));
binding.setData(data);
}
39. z
Do the binding
On the activity
Give the data object to the binding for the painting
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ViewData data = new ViewData(getString(R.string.hello_world));
binding.setData(data);
}
41. z
Other things to do
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_offer”
android:visibility="@{product.isOffer? View.VISIBLE : View.GONE}"/>
<data>
<import type="android.view.View"/>
<variable name=“product” type=“com.sergiandreplace.hellodatabinding.product”/>
</data>
42. z
More things to do
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{StringUtils.getFormatCurrency(product.price, product.currency)}”
/>
<data>
<import type="com.sergiandreplace.hellodatabinding.StringUtils"/>
<variable name=“product” type=“com.sergiandreplace.hellodatabinding.product”/>
</data>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{StringUtils.getFormatCurrency(product.Price) + product.currency}”
/>
43. z
Include with Binding
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name=“product" type=“com.sergiandreplace.hellodatabinding.Product"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/header"
bind:product="@{product}"/>
<include layout="@layout/detail"
bind:product="@{product}"/>
</LinearLayout>
</layout>
Merge not supported
46. z
Observable objects
private static class Product extends BaseObservable {
private String name;
private String description;
@Bindable
public String getName() {
return this.name;
}
@Bindable
public String getDescription() {
return this.description;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setLastName(String description) {
this. description = description;
notifyPropertyChanged(BR. description);
}
}
47. z
Observable objects
Extends BaseObservable
private static class Product extends BaseObservable {
private String name;
private String description;
@Bindable
public String getName() {
return this.name;
}
@Bindable
public String getDescription() {
return this.description;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setLastName(String description) {
this. description = description;
notifyPropertyChanged(BR. description);
}
}
48. z
Observable objects
Declare getters as bindable
private static class Product extends BaseObservable {
private String name;
private String description;
@Bindable
public String getName() {
return this.name;
}
@Bindable
public String getDescription() {
return this.description;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setLastName(String description) {
this. description = description;
notifyPropertyChanged(BR. description);
}
}
49. z
Observable objects
Notify changes
BR is like R for Bindables (aka: magic generated on compilation)
private static class Product extends BaseObservable {
private String name;
private String description;
@Bindable
public String getName() {
return this.name;
}
@Bindable
public String getDescription() {
return this.description;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setLastName(String description) {
this. description = description;
notifyPropertyChanged(BR.description);
}
}
50. z
Even easier: observable fields
private static class Product{
public final ObservableField<String> name =
new ObservableField<>();
public final ObservableField<String> description =
new ObservableField<>();
public final ObservableInt stock = new ObservableInt();
}
51. z
Even easier: observable fields
ObservableField just uses generics for any class
private static class Product{
public final ObservableField<String> name =
new ObservableField<>();
public final ObservableField<String> description =
new ObservableField<>();
public final ObservableInt stock = new ObservableInt();
}
52. z
Even easier: observable fields
ObservableInt, ObservableLong, ObservableParcelable, etc, already usable
private static class Product{
public final ObservableField<String> name =
new ObservableField<>();
public final ObservableField<String> description =
new ObservableField<>();
public final ObservableInt stock = new ObservableInt();
}
53. z
Even easier: observable fields
To use them…
private static class Product{
public final ObservableField<String> name =
new ObservableField<>();
public final ObservableField<String> description =
new ObservableField<>();
public final ObservableInt stock = new ObservableInt();
}
Product.stock.get();
product.name.set(“Biscuits”);
54. Attribute setters
Binding library tries to match the attribute setter with
attribute name
Ex: on android:text=“@{…}” it looks for the setText method
In some cases we want something more accurated
We can create our own attribute setters
56. Attribute setters
Not available for custom namespaces
Multiple parameters available
@BindingAdapter({"bind:imageUrl", "bind:error"})
public static void loadImage(ImageView view, String url, Drawable error) {
Picasso.with(view.getContext()).load(url).error(error).into(view);
}
<ImageView app:imageUrl=“@{venue.imageUrl}”
app:error=“@{@drawable/venueError}”/>
57. There is even more
Converters
Arrays and lists handling
Messing up with lists
ViewStubs!
Dynamic variables
58. But enough for today
We are all discovering it and learning what can be done
Play around with it
Check articles of really cool people on the Internet
59. For last…
Let’s talk a bit about architectures
• MVC – Model-View-Controller
• MVP – Model-View-Presenter
• MVVM – Model-View-ViewModel
61. Final big advice
Do not put business logic in the View Model
CLEARLY separate business-logic and representation-logic
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/discount”
android:visibility="@{product.isOffer? 0.15 : 0}"/>
62. Final big advice
Do not put business logic in the View Model
CLEARLY separate business-logic and representation-logic
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/discount”
android:visibility="@{product.isOffer? 0.15 : 0}"/>
64. 20 yrs tinkering with computers
A lot of time on software localization
On Android since 2010 (Cupcake)
Mobile R+D Lead at Worldine Iberia
Android GDE (Google Developer
Expert)
I love making UI
Proud parent of a 8 years old OS fan
@sergiandreplace
sergiandreplace.com
sergi.Martinez[at]gmail.com
About me – Sergi Martínez