KEMBAR78
Android data binding | PPTX
Android data binding
The rules of the game have changed
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
Android data binding
Introduced by Google in I/O 2015 (almost unnoticed)
But really important. It will change the way we make UIs
Google dixit
Writing declarative layouts and minimize the
glue code necessary to bind your application
logic and layouts.
Data Binding library is for...
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
But before…
Let’s talk about inflation…
What’s inflation?
Inflation is the process used by Android to
transform XML layouts into a tree of View
objects.
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);
}
}
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
z
Some code (using custom inflater)
New inflater defined as InflaterFactory
z
Some code (using custom inflater)
New inflater defined as InflaterFactory
z
Some code (using custom inflater)
Once we set a new InflatorFactory, we are ready for inflation
z
More code (hacking the code inflater)
z
More code (hacking the code inflater)
z
More code (hacking the code inflater)
z
More code (hacking the code inflater)
z
More code (hacking the code inflater)
Custom code
The whole example
Check it out on
https://github.com/sergiandreplace/AndroidFontInflaterFactory
(old Eclipse structure)
Also an experiment, use at your own risk
And now…
Let’s start with data binding…
…but…
WARNING
Data binding is in beta state
Use at your own risk
Could suffer several changes
Could have bugs
DO NOT USE IN PRODUCTION
Steps to follow
1. Add Data Binding library
2. Apply binding to layout
3. Create data binding object
4. Do the binding
z
Adding Data Binding library
Project build.gradle
App build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath "com.android.databinding:dataBinder:1.0-rc1"
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
z
Adding Data Binding library
Project build.gradle
App build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath "com.android.databinding:dataBinder:1.0-rc1"
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
z
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
Adding Data Binding library
Project build.gradle
App build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath "com.android.databinding:dataBinder:1.0-rc1"
}
}
z
Adding Data Binding library
Project build.gradle
App build.gradle
…and sync gradle!
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath "com.android.databinding:dataBinder:1.0-rc1"
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
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>
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>
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>
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>
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>
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>
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;
}
}
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;
}
}
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;
}
}
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);
}
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);
}
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
}
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);
}
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);
}
Execute…
…and it works!
Pretty exciting, isn’t it?
Not really
Let’s see some other things we can do
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>
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}”
/>
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 
Supported operators
Mathematical + - / * %
String concatenation +
Logical && ||
Binary & | ^
Unary + - ! ~
Shift >> >>> <<
Comparison == > < >= <=
Null ?? (a??b = a==null?b:a)
instanceof
Grouping ()
Literals - character, String, numeric, null
Cast
Method calls
Field access
Array access []
Ternary operator ?:
z
Even list handling!
<data>
<import type="android.util.SparseArray"/>
<import type="java.util.Map"/>
<import type="java.util.List"/>
<variable name="list" type="List&lt;String>"/>
<variable name="sparse" type="SparseArray&lt;String>"/>
<variable name="map" type="Map&lt;String, String>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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();
}
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();
}
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();
}
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”);
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
z
Attribute Setters
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
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}”/>
There is even more
Converters
Arrays and lists handling
Messing up with lists
ViewStubs!
Dynamic variables
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
For last…
Let’s talk a bit about architectures
• MVC – Model-View-Controller
• MVP – Model-View-Presenter
• MVVM – Model-View-ViewModel
Basic comparison
From Geeks with blog (geekswithblogs.net)
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}"/>
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}"/>
Q
A
uestions
nswers
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

Android data binding

  • 1.
    Android data binding Therules of the game have changed
  • 2.
    20 yrs tinkeringwith 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 Introducedby Google in I/O 2015 (almost unnoticed) But really important. It will change the way we make UIs
  • 4.
    Google dixit Writing declarativelayouts and minimize the glue code necessary to bind your application logic and layouts. Data Binding library is for...
  • 5.
    What is databinding? 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
  • 6.
    But before… Let’s talkabout inflation…
  • 7.
    What’s inflation? Inflation isthe process used by Android to transform XML layouts into a tree of View objects.
  • 8.
    z Inflation process Inflate as Oralso 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 (usingcustom inflater) New inflater defined as InflaterFactory
  • 11.
    z Some code (usingcustom inflater) New inflater defined as InflaterFactory
  • 12.
    z Some code (usingcustom inflater) Once we set a new InflatorFactory, we are ready for inflation
  • 13.
    z More code (hackingthe code inflater)
  • 14.
    z More code (hackingthe code inflater)
  • 15.
    z More code (hackingthe code inflater)
  • 16.
    z More code (hackingthe code inflater)
  • 17.
    z More code (hackingthe code inflater) Custom code
  • 18.
    The whole example Checkit out on https://github.com/sergiandreplace/AndroidFontInflaterFactory (old Eclipse structure) Also an experiment, use at your own risk
  • 19.
    And now… Let’s startwith data binding… …but…
  • 20.
    WARNING Data binding isin beta state Use at your own risk Could suffer several changes Could have bugs DO NOT USE IN PRODUCTION
  • 21.
    Steps to follow 1.Add Data Binding library 2. Apply binding to layout 3. Create data binding object 4. Do the binding
  • 22.
    z Adding Data Bindinglibrary Project build.gradle App build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } } apply plugin: 'com.android.application' apply plugin: 'com.android.databinding'
  • 23.
    z Adding Data Bindinglibrary Project build.gradle App build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } } apply plugin: 'com.android.application' apply plugin: 'com.android.databinding'
  • 24.
    z apply plugin: 'com.android.application' applyplugin: 'com.android.databinding' Adding Data Binding library Project build.gradle App build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } }
  • 25.
    z Adding Data Bindinglibrary Project build.gradle App build.gradle …and sync gradle! buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } } apply plugin: 'com.android.application' apply plugin: 'com.android.databinding'
  • 26.
    z Apply binding tolayout 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 tolayout 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 tolayout 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 tolayout 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 tolayout 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 tolayout 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 bindingobject 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 bindingobject 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 bindingobject 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 Onthe 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 Onthe 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 Onthe 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 Onthe 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 Onthe 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); }
  • 40.
    Execute… …and it works! Prettyexciting, isn’t it? Not really Let’s see some other things we can do
  • 41.
    z Other things todo <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 todo <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 <?xmlversion="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 
  • 44.
    Supported operators Mathematical +- / * % String concatenation + Logical && || Binary & | ^ Unary + - ! ~ Shift >> >>> << Comparison == > < >= <= Null ?? (a??b = a==null?b:a) instanceof Grouping () Literals - character, String, numeric, null Cast Method calls Field access Array access [] Ternary operator ?:
  • 45.
    z Even list handling! <data> <importtype="android.util.SparseArray"/> <import type="java.util.Map"/> <import type="java.util.List"/> <variable name="list" type="List&lt;String>"/> <variable name="sparse" type="SparseArray&lt;String>"/> <variable name="map" type="Map&lt;String, String>"/> <variable name="index" type="int"/> <variable name="key" type="String"/> </data> … android:text="@{list[index]}" … android:text="@{sparse[index]}" … android:text="@{map[key]}"
  • 46.
    z Observable objects private staticclass 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 privatestatic 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 gettersas 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 BRis 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: observablefields 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: observablefields 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: observablefields 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: observablefields 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 librarytries 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
  • 55.
    z Attribute Setters @BindingAdapter("android:paddingLeft") public staticvoid setPaddingLeft(View view, int padding) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); }
  • 56.
    Attribute setters Not availablefor 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 evenmore Converters Arrays and lists handling Messing up with lists ViewStubs! Dynamic variables
  • 58.
    But enough fortoday 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 talka bit about architectures • MVC – Model-View-Controller • MVP – Model-View-Presenter • MVVM – Model-View-ViewModel
  • 60.
    Basic comparison From Geekswith blog (geekswithblogs.net)
  • 61.
    Final big advice Donot 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 Donot 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}"/>
  • 63.
  • 64.
    20 yrs tinkeringwith 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