SlideShare a Scribd company logo
#dfua
And Design Guidelines
Data Binding. Next big thing?
Anton Minashkin
Developer @ GlobalLogic
#dfua
What is Data Binding?
Data + UI = Data Binding
MVC => MV*
#dfua
How it looks now?..
#dfua
Design
#dfua
Layout
<AutoCompleteTextView
android:id="@+id/email"
.../>
<EditText
android:id="@+id/password"
.../>
<Button
android:id="@+id/email_sign_in_button"
... />
Login.xml
#dfua
Init views
// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
…
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mPasswordView = (EditText) findViewById(R.id.password);
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
…
}
LoginActivity.java
#dfua
Init views
// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
…
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mPasswordView = (EditText) findViewById(R.id.password);
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
…
}
LoginActivity.java
#dfua
Add behavior
...
mEmailView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mEmailSignInButton.setText(String.format(getString(R.string.action_sign_in), s));
}
@Override
public void afterTextChanged(Editable s) {
}
});
...
LoginActivity.java
#dfua
Add behavior
...
mEmailView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mEmailSignInButton.setText(String.format(getString(R.string.action_sign_in), s));
}
@Override
public void afterTextChanged(Editable s) {
}
});
...
LoginActivity.java
#dfua
Add behavior
@Override
protected void onCreate(Bundle savedInstanceState) {
...
Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
mEmailSignInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
attemptLogin();
}
});
…
}
LoginActivity.java
#dfua
Add behavior
private void attemptLogin() {
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
doLogin(email, password);
}
}
LoginActivity.java
#dfua
#dfua
Data Binding
Meanwhile in perfect world...
#dfua
(View) Model
public class LoginForm {
private String mLogin = "login";
private String mPassword = "password";
...
//getXXX & setXXX
...
public void doLogin() {
...
}
}
LoginForm.java
#dfua
Layout + Data Binding
<AutoCompleteTextView
android:id="@+id/email"
android:onTextUpdate="@{loginForm.setLogin}"
.../>
<EditText
android:id="@+id/password"
android:onTextUpdate="@{loginForm.setPassword}"
.../>
<Button
android:id="@+id/email_sign_in_button"
android:text="@{String.format(@string/action_sign_in, loginForm.login)}"
android:click="{loginForm.doLogin}"
... />
activity_login.xml
#dfua
Layout + Data Binding
<AutoCompleteTextView
android:id="@+id/email"
android:onTextUpdate="@{loginForm.setLogin}"
.../>
<EditText
android:id="@+id/password"
android:onTextUpdate="@{loginForm.setPassword}"
.../>
<Button
android:id="@+id/email_sign_in_button"
android:text="@{String.format(@string/action_sign_in, loginForm.login)}"
android:click="{loginForm.doLogin}"
... />
activity_login.xml
#dfua
Layout + Data Binding
public class LoginForm extends BaseObservable {
private String mLogin = "login";
private String mPassword = "password";
public void doLogin(View v) {
...
}
}
LoginForm.java
#dfua
Layout + Data Binding
public class LoginForm extends BaseObservable {
...
@Bindable
public String getPassword() {
return mPassword;
}
@Bindable
public String getLogin() {
return mLogin;
}
...
}
LoginForm.java
#dfua
Layout + Data Binding
public class LoginForm extends BaseObservable {
...
public void setPassword(String password) {
this.mPassword = password;
notifyPropertyChanged(BR.password);
}
public void setLogin(String login) {
this.mLogin = login;
notifyPropertyChanged(BR.login);
}
...
}
LoginForm.java
#dfua
Layout + Data Binding
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="loginForm" type="grmm.org.gdg.LoginForm" />
</data>
...
</layout>
activity_login.xml
#dfua
Layout + Data Binding
<AutoCompleteTextView
android:id="@+id/email"
android:onTextUpdate="@{loginForm.setLogin}"
.../>
<EditText
android:id="@+id/password"
android:onTextUpdate="@{loginForm.setPassword}"
.../>
<Button
android:id="@+id/email_sign_in_button"
android:text="@{String.format(@string/action_sign_in, loginForm.login)}"
android:click="{loginForm.doLogin}"
... />
activity_login.xml
#dfua
Layout + Data Binding
public interface UpdateText {
void updateText(String s);
}
UpdateText.java
#dfua
Layout + Data Binding
@BindingAdapter("android:onTextUpdate")
public static void setListener(EditText view, final UpdateText callback) {
...
TextWatcher newWatcher = new TextWatcher() {
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
callback.updateText(s.toString());
}
...
};
view.addTextChangedListener(newWatcher);
...
}
EditTextUtils.java
#dfua
Layout + Data Binding
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ActivityLoginBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_login);
binding.setLoginForm(new LoginForm());
}
MainActivity.java
#dfua
Design
#dfua
Layout
Make your UI more smart
#dfua
Layout
● Data section
● Includes
● Expression language
#dfua
Data section
<data>
<import type="com.example.User"/>
<import type="java.util.List"/>
<variable name="user" type="User"/>
<variable name="userList" type="List<User>"/>
</data>
activity_login.xml
#dfua
Includes
<?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="user" type="com.example.User"/>
</data>
<LinearLayout ...>
<include layout="@layout/name"
bind:user="@{user}"/>
<include layout="@layout/contact"
bind:user="@{user.contact}"/>
</LinearLayout>
</layout>
layout.xml
#dfua
Includes
<?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="user" type="com.example.User"/>
</data>
<LinearLayout ...>
<include layout="@layout/name"
bind:user="@{user}"/>
<include layout="@layout/contact"
bind:user="@{user.contact}"/>
</LinearLayout>
</layout>
layout.xml
#dfua
Expression language. Commons
Mathematical + - / * %
String concatenation +
Logical && ||
Binary & | ^
Unary + - ! ~
Shift >> >>> <<
Comparison == > < >= <=
instanceof
Grouping ()
Literals - character, String, numeric, null
Cast
Method calls
Field access
Array access []
Ternary operator ?:
#dfua
Expression language. Commons
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
layout.xml
#dfua
Expression language. Null Handling
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
Equals
android:text="@{user.displayName ?? user.lastName}"
…
android:text="@{user.contact.primaryPhoneNumber}" //String - NULL
android:width="@{form.size.width}" //Int - 0
layout.xml
#dfua
Expression language. Collections & Resources
android:text="@{list[index]}"
android:text="@{sparse[index]}"
android:text="@{map[key]}"
...
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"
layout.xml
#dfua
Expression language. Limitations
● this
● super
● new
#dfua
Data Objects
Notify me fully
#dfua
Data Objects
● Observable Objects
● ObservableFields
● Observable Collections
#dfua
Observable objects
● Should implement Observable
● ...or extend BaseObservable
● Should call notifyPropertyChanged(...) when modified
● Should use @Bindable for fields/getters
#dfua
Observable objects
class Address extends BaseObservable {
private String address;
@Bindable
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
notifyPropertyChanged(BR.address);
}
}
Address.java
#dfua
ObservableFields
Base class ObservableField
Siblings: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort,
ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and
ObservableParcelable, ObservableField<T>
#dfua
ObservableFields
private static class User {
public final ObservableField<String> firstName = new ObservableField<>();
public final ObservableField<String> lastName = new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
...
user.firstName.set("Google");
int age = user.age.get();
User.java
#dfua
Observable Collections
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Bob");
user.put("lastName", "Smit");
...
ObservableArrayList<String> strings = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add("Some other string");
Example.java
#dfua
Generated Bindings
UI from other side
#dfua
Create
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);
...
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
...
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId,
parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);
Example.java
#dfua
Views
...
<AutoCompleteTextView android:id="@+id/email" />
<EditText android:id="@+id/password" />
<Button android:id="@+id/email_sign_in_button" />
...
public final TextView email;
public final TextView password;
public final Button emailSignInButton;
Login.xml
#dfua
Variables
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
...
public abstract com.example.User getUser();
public abstract void setUser(com.example.User user);
public abstract Drawable getImage();
public abstract void setImage(Drawable image);
public abstract String getNote();
public abstract void setNote(String note);
Login.xml
#dfua
Attribute setters
Extend your XML
#dfua
Attribute setters
<AutoCompleteTextView
android:id="@+id/email"
android:onTextUpdate="@{loginForm.setLogin}"
.../>
<EditText
android:id="@+id/password"
android:onTextUpdate="@{loginForm.setPassword}"
.../>
Login.xml
#dfua
Attribute setters
@BindingAdapter("android:onTextUpdate")
public static void setListener(EditText view, final UpdateText callback) {
...
TextWatcher newWatcher = new TextWatcher() {
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
callback.updateText(s.toString());
}
...
};
view.addTextChangedListener(newWatcher);
...
}
EditTextUtils.java
#dfua
Attribute setters
@BindingAdapter("android:onTextUpdate")
public static void setListener(EditText view, final UpdateText callback) {
...
TextWatcher newWatcher = new TextWatcher() {
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
callback.updateText(s.toString());
}
...
};
view.addTextChangedListener(newWatcher);
...
}
EditTextUtils.java
#dfua
Attribute setters
@BindingAdapter("android:onTextUpdate")
public static void setListener(EditText view, final UpdateText callback) {
...
TextWatcher newWatcher = new TextWatcher() {
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
callback.updateText(s.toString());
}
...
};
view.addTextChangedListener(newWatcher);
...
}
EditTextUtils.java
#dfua
Attribute setters
<ImageView
app:imageUrl=“@{venue.imageUrl}”
app:error=“@{@drawable/venueError}”
/>
...
@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);
}
ImageUtils.java
#dfua
Attribute setters. Old vs New
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
if (oldPadding != newPadding) {
view.setPadding(newPadding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
}
ViewUtils.java
#dfua
Attribute setters. Event handlers
@BindingAdapter("android:onLayoutChange")
public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener
oldValue,
View.OnLayoutChangeListener newValue) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (oldValue != null) {
view.removeOnLayoutChangeListener(oldValue);
}
if (newValue != null) {
view.addOnLayoutChangeListener(newValue);
}
}
}
ViewUtils.java
#dfua
Attribute setters. Event handlers
@BindingAdapter("android:onTextUpdate")
public static void setListener(EditText view, final UpdateText callback) {
...
TextWatcher newWatcher = new TextWatcher() {
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
callback.updateText(s.toString());
}
...
};
view.addTextChangedListener(newWatcher);
...
}
EditTextUtils.java
#dfua
How to add?
dependencies {
classpath "com.android.tools.build:gradle:1.3.0"
classpath "com.android.databinding:dataBinder:1.0-rc2"
}
…
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
build.gradle
#dfua
Summary
Use it!
#dfua
Summary
● MVVM
● Less code
● More Value
● Easy to test (Unit tests, Unit test, Unit test!)
● API Level 7+
● Works like Magic
#dfua
Thank you!
Questions?Questions?
@AntonMinashkin
G+ https://goo.gl/ou9NPS
anton.minashkin@outlook.com

More Related Content

Data Binding: Is It the Next Big Thing?

  • 1. #dfua And Design Guidelines Data Binding. Next big thing? Anton Minashkin Developer @ GlobalLogic
  • 2. #dfua What is Data Binding? Data + UI = Data Binding MVC => MV*
  • 6. #dfua Init views // UI references. private AutoCompleteTextView mEmailView; private EditText mPasswordView; … @Override protected void onCreate(Bundle savedInstanceState) { ... mPasswordView = (EditText) findViewById(R.id.password); mEmailView = (AutoCompleteTextView) findViewById(R.id.email); … } LoginActivity.java
  • 7. #dfua Init views // UI references. private AutoCompleteTextView mEmailView; private EditText mPasswordView; … @Override protected void onCreate(Bundle savedInstanceState) { ... mPasswordView = (EditText) findViewById(R.id.password); mEmailView = (AutoCompleteTextView) findViewById(R.id.email); Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); … } LoginActivity.java
  • 8. #dfua Add behavior ... mEmailView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mEmailSignInButton.setText(String.format(getString(R.string.action_sign_in), s)); } @Override public void afterTextChanged(Editable s) { } }); ... LoginActivity.java
  • 9. #dfua Add behavior ... mEmailView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mEmailSignInButton.setText(String.format(getString(R.string.action_sign_in), s)); } @Override public void afterTextChanged(Editable s) { } }); ... LoginActivity.java
  • 10. #dfua Add behavior @Override protected void onCreate(Bundle savedInstanceState) { ... Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); mEmailSignInButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { attemptLogin(); } }); … } LoginActivity.java
  • 11. #dfua Add behavior private void attemptLogin() { String email = mEmailView.getText().toString(); String password = mPasswordView.getText().toString(); doLogin(email, password); } } LoginActivity.java
  • 12. #dfua
  • 14. #dfua (View) Model public class LoginForm { private String mLogin = "login"; private String mPassword = "password"; ... //getXXX & setXXX ... public void doLogin() { ... } } LoginForm.java
  • 15. #dfua Layout + Data Binding <AutoCompleteTextView android:id="@+id/email" android:onTextUpdate="@{loginForm.setLogin}" .../> <EditText android:id="@+id/password" android:onTextUpdate="@{loginForm.setPassword}" .../> <Button android:id="@+id/email_sign_in_button" android:text="@{String.format(@string/action_sign_in, loginForm.login)}" android:click="{loginForm.doLogin}" ... /> activity_login.xml
  • 16. #dfua Layout + Data Binding <AutoCompleteTextView android:id="@+id/email" android:onTextUpdate="@{loginForm.setLogin}" .../> <EditText android:id="@+id/password" android:onTextUpdate="@{loginForm.setPassword}" .../> <Button android:id="@+id/email_sign_in_button" android:text="@{String.format(@string/action_sign_in, loginForm.login)}" android:click="{loginForm.doLogin}" ... /> activity_login.xml
  • 17. #dfua Layout + Data Binding public class LoginForm extends BaseObservable { private String mLogin = "login"; private String mPassword = "password"; public void doLogin(View v) { ... } } LoginForm.java
  • 18. #dfua Layout + Data Binding public class LoginForm extends BaseObservable { ... @Bindable public String getPassword() { return mPassword; } @Bindable public String getLogin() { return mLogin; } ... } LoginForm.java
  • 19. #dfua Layout + Data Binding public class LoginForm extends BaseObservable { ... public void setPassword(String password) { this.mPassword = password; notifyPropertyChanged(BR.password); } public void setLogin(String login) { this.mLogin = login; notifyPropertyChanged(BR.login); } ... } LoginForm.java
  • 20. #dfua Layout + Data Binding <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="loginForm" type="grmm.org.gdg.LoginForm" /> </data> ... </layout> activity_login.xml
  • 21. #dfua Layout + Data Binding <AutoCompleteTextView android:id="@+id/email" android:onTextUpdate="@{loginForm.setLogin}" .../> <EditText android:id="@+id/password" android:onTextUpdate="@{loginForm.setPassword}" .../> <Button android:id="@+id/email_sign_in_button" android:text="@{String.format(@string/action_sign_in, loginForm.login)}" android:click="{loginForm.doLogin}" ... /> activity_login.xml
  • 22. #dfua Layout + Data Binding public interface UpdateText { void updateText(String s); } UpdateText.java
  • 23. #dfua Layout + Data Binding @BindingAdapter("android:onTextUpdate") public static void setListener(EditText view, final UpdateText callback) { ... TextWatcher newWatcher = new TextWatcher() { ... @Override public void onTextChanged(CharSequence s, int start, int before, int count) { callback.updateText(s.toString()); } ... }; view.addTextChangedListener(newWatcher); ... } EditTextUtils.java
  • 24. #dfua Layout + Data Binding @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); ActivityLoginBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_login); binding.setLoginForm(new LoginForm()); } MainActivity.java
  • 27. #dfua Layout ● Data section ● Includes ● Expression language
  • 28. #dfua Data section <data> <import type="com.example.User"/> <import type="java.util.List"/> <variable name="user" type="User"/> <variable name="userList" type="List<User>"/> </data> activity_login.xml
  • 29. #dfua Includes <?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="user" type="com.example.User"/> </data> <LinearLayout ...> <include layout="@layout/name" bind:user="@{user}"/> <include layout="@layout/contact" bind:user="@{user.contact}"/> </LinearLayout> </layout> layout.xml
  • 30. #dfua Includes <?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="user" type="com.example.User"/> </data> <LinearLayout ...> <include layout="@layout/name" bind:user="@{user}"/> <include layout="@layout/contact" bind:user="@{user.contact}"/> </LinearLayout> </layout> layout.xml
  • 31. #dfua Expression language. Commons Mathematical + - / * % String concatenation + Logical && || Binary & | ^ Unary + - ! ~ Shift >> >>> << Comparison == > < >= <= instanceof Grouping () Literals - character, String, numeric, null Cast Method calls Field access Array access [] Ternary operator ?:
  • 32. #dfua Expression language. Commons android:text="@{String.valueOf(index + 1)}" android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}" android:transitionName='@{"image_" + id}' layout.xml
  • 33. #dfua Expression language. Null Handling android:text="@{user.displayName != null ? user.displayName : user.lastName}" Equals android:text="@{user.displayName ?? user.lastName}" … android:text="@{user.contact.primaryPhoneNumber}" //String - NULL android:width="@{form.size.width}" //Int - 0 layout.xml
  • 34. #dfua Expression language. Collections & Resources android:text="@{list[index]}" android:text="@{sparse[index]}" android:text="@{map[key]}" ... android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}" android:text="@{@string/nameFormat(firstName, lastName)}" android:text="@{@plurals/banana(bananaCount)}" layout.xml
  • 37. #dfua Data Objects ● Observable Objects ● ObservableFields ● Observable Collections
  • 38. #dfua Observable objects ● Should implement Observable ● ...or extend BaseObservable ● Should call notifyPropertyChanged(...) when modified ● Should use @Bindable for fields/getters
  • 39. #dfua Observable objects class Address extends BaseObservable { private String address; @Bindable public String getAddress() { return this.address; } public void setAddress(String address) { this.address = address; notifyPropertyChanged(BR.address); } } Address.java
  • 40. #dfua ObservableFields Base class ObservableField Siblings: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable, ObservableField<T>
  • 41. #dfua ObservableFields private static class User { public final ObservableField<String> firstName = new ObservableField<>(); public final ObservableField<String> lastName = new ObservableField<>(); public final ObservableInt age = new ObservableInt(); } ... user.firstName.set("Google"); int age = user.age.get(); User.java
  • 42. #dfua Observable Collections ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); user.put("firstName", "Bob"); user.put("lastName", "Smit"); ... ObservableArrayList<String> strings = new ObservableArrayList<>(); user.add("Google"); user.add("Inc."); user.add("Some other string"); Example.java
  • 44. #dfua Create MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater); MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false); ... MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot); ... ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId, parent, attachToParent); ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId); Example.java
  • 45. #dfua Views ... <AutoCompleteTextView android:id="@+id/email" /> <EditText android:id="@+id/password" /> <Button android:id="@+id/email_sign_in_button" /> ... public final TextView email; public final TextView password; public final Button emailSignInButton; Login.xml
  • 46. #dfua Variables <data> <import type="android.graphics.drawable.Drawable"/> <variable name="user" type="com.example.User"/> <variable name="image" type="Drawable"/> <variable name="note" type="String"/> </data> ... public abstract com.example.User getUser(); public abstract void setUser(com.example.User user); public abstract Drawable getImage(); public abstract void setImage(Drawable image); public abstract String getNote(); public abstract void setNote(String note); Login.xml
  • 49. #dfua Attribute setters @BindingAdapter("android:onTextUpdate") public static void setListener(EditText view, final UpdateText callback) { ... TextWatcher newWatcher = new TextWatcher() { ... @Override public void onTextChanged(CharSequence s, int start, int before, int count) { callback.updateText(s.toString()); } ... }; view.addTextChangedListener(newWatcher); ... } EditTextUtils.java
  • 50. #dfua Attribute setters @BindingAdapter("android:onTextUpdate") public static void setListener(EditText view, final UpdateText callback) { ... TextWatcher newWatcher = new TextWatcher() { ... @Override public void onTextChanged(CharSequence s, int start, int before, int count) { callback.updateText(s.toString()); } ... }; view.addTextChangedListener(newWatcher); ... } EditTextUtils.java
  • 51. #dfua Attribute setters @BindingAdapter("android:onTextUpdate") public static void setListener(EditText view, final UpdateText callback) { ... TextWatcher newWatcher = new TextWatcher() { ... @Override public void onTextChanged(CharSequence s, int start, int before, int count) { callback.updateText(s.toString()); } ... }; view.addTextChangedListener(newWatcher); ... } EditTextUtils.java
  • 52. #dfua Attribute setters <ImageView app:imageUrl=“@{venue.imageUrl}” app:error=“@{@drawable/venueError}” /> ... @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); } ImageUtils.java
  • 53. #dfua Attribute setters. Old vs New @BindingAdapter("android:paddingLeft") public static void setPaddingLeft(View view, int oldPadding, int newPadding) { if (oldPadding != newPadding) { view.setPadding(newPadding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); } } ViewUtils.java
  • 54. #dfua Attribute setters. Event handlers @BindingAdapter("android:onLayoutChange") public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue, View.OnLayoutChangeListener newValue) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { if (oldValue != null) { view.removeOnLayoutChangeListener(oldValue); } if (newValue != null) { view.addOnLayoutChangeListener(newValue); } } } ViewUtils.java
  • 55. #dfua Attribute setters. Event handlers @BindingAdapter("android:onTextUpdate") public static void setListener(EditText view, final UpdateText callback) { ... TextWatcher newWatcher = new TextWatcher() { ... @Override public void onTextChanged(CharSequence s, int start, int before, int count) { callback.updateText(s.toString()); } ... }; view.addTextChangedListener(newWatcher); ... } EditTextUtils.java
  • 56. #dfua How to add? dependencies { classpath "com.android.tools.build:gradle:1.3.0" classpath "com.android.databinding:dataBinder:1.0-rc2" } … apply plugin: 'com.android.application' apply plugin: 'com.android.databinding' build.gradle
  • 58. #dfua Summary ● MVVM ● Less code ● More Value ● Easy to test (Unit tests, Unit test, Unit test!) ● API Level 7+ ● Works like Magic