Data Binding: Is It the Next Big Thing?
- 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
- 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
- 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 ?:
- 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
- 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
- 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
- 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
- 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