android data binding

64
Android data binding The rules of the game have changed

Upload: sergi-martinez

Post on 07-Jan-2017

2.921 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Android data binding

Android data binding

The rules of the game have changed

Page 2: Android data binding

20 yrs tinkering with computersA lot of time on software localizationOn Android since 2010 (Cupcake)Mobile R+D Lead at Worldine IberiaAndroid GDE (Google Developer Expert)I love making UIProud parent of a 8 years old OS fan

@sergiandreplace

sergiandreplace.comsergi.Martinez[at]gmail.com

About me – Sergi Martínez

Page 3: Android data binding

Android data binding

Introduced by Google in I/O 2015 (almost unnoticed)

But really important. It will change the way we make UIs

Page 4: Android data binding

Google dixit

Writing declarative layouts and minimize the glue code necessary to

bind your application logic and layouts.

Data Binding library is for...

Page 5: Android data binding

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

Page 6: Android data binding

But before…

Let’s talk about inflation…

Page 7: Android data binding

What’s inflation?

Inflation is the process used by Android to transform XML layouts into

a tree of View objects.

Page 8: Android data binding

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); }

}

Page 9: Android data binding

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 propertiesIf fails: hell on earth

Page 10: Android data binding

z

Some code (using custom inflater)

New inflater defined as InflaterFactory

Page 11: Android data binding

z

Some code (using custom inflater)

New inflater defined as InflaterFactory

Page 12: Android data binding

z

Some code (using custom inflater)

Once we set a new InflatorFactory, we are ready for inflation

Page 13: Android data binding

z

More code (hacking the code inflater)

Page 14: Android data binding

z

More code (hacking the code inflater)

Page 15: Android data binding

z

More code (hacking the code inflater)

Page 16: Android data binding

z

More code (hacking the code inflater)

Page 17: Android data binding

z

More code (hacking the code inflater)

Custom code

Page 18: Android data binding

The whole example

Check it out on https://

github.com/sergiandreplace/AndroidFontInflaterFactory(old Eclipse structure)

Also an experiment, use at your own risk

Page 19: Android data binding

And now…

Let’s start with data binding…

…but…

Page 20: Android data binding

WARNING

Data binding is in beta state

Use at your own risk

Could suffer several changes

Could have bugs

DO NOT USE IN PRODUCTION

Page 21: Android data binding

Steps to follow

1. Add Data Binding library2. Apply binding to layout3. Create data binding object4. Do the binding

Page 22: Android data 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'

Page 23: Android data 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'

Page 24: Android data binding

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"

}}

Page 25: Android data binding

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'

Page 26: Android data binding

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>

Page 27: Android data binding

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>

Page 28: Android data binding

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>

Page 29: Android data binding

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>

Page 30: Android data binding

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>

Page 31: Android data binding

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>

Page 32: Android data binding

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;

}

}

Page 33: Android data binding

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;

}

}

Page 34: Android data binding

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;

}

}

Page 35: Android data binding

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);

}

Page 36: Android data binding

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);

}

Page 37: Android data binding

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 recognizeOnly 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

}

Page 38: Android data binding

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);

}

Page 39: Android data binding

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);

}

Page 40: Android data binding

Execute…

…and it works!Pretty exciting, isn’t it?Not reallyLet’s see some other things we can do

Page 41: Android data binding

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>

Page 42: Android data binding

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}”

           />

Page 43: Android data binding

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

Page 44: Android data binding

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 ?:

Page 45: Android data binding

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]}"

Page 46: Android data binding

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);   }}

Page 47: Android data binding

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);   }}

Page 48: Android data binding

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);   }}

Page 49: Android data binding

z

Observable objects

Notify changesBR 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);   }}

Page 50: Android data binding

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();

}

Page 51: Android data binding

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();

}

Page 52: Android data binding

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();

}

Page 53: Android data binding

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”);

Page 54: Android data binding

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

Page 55: Android data binding

z

Attribute Setters

@BindingAdapter("android:paddingLeft")

public static void setPaddingLeft(View view, int padding) {

   view.setPadding(padding,

                   view.getPaddingTop(),

                   view.getPaddingRight(),

                   view.getPaddingBottom());

}

Page 56: Android data binding

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}”/>

Page 57: Android data binding

There is even more

ConvertersArrays and lists handlingMessing up with listsViewStubs!Dynamic variables

Page 58: Android data binding

But enough for today

We are all discovering it and learning what can be donePlay around with itCheck articles of really cool people on the Internet

Page 59: Android data binding

For last…

Let’s talk a bit about architectures

• MVC – Model-View-Controller

• MVP – Model-View-Presenter

• MVVM – Model-View-ViewModel

Page 60: Android data binding

Basic comparison

From Geeks with blog (geekswithblogs.net)

Page 61: Android data binding

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}"/>

Page 62: Android data binding

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}"/>

Page 63: Android data binding

QA

uestions

nswers

Page 64: Android data binding

20 yrs tinkering with computersA lot of time on software localizationOn Android since 2010 (Cupcake)Mobile R+D Lead at Worldine IberiaAndroid GDE (Google Developer Expert)I love making UIProud parent of a 8 years old OS fan

@sergiandreplace

sergiandreplace.comsergi.Martinez[at]gmail.com

About me – Sergi Martínez