Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Anton Minashkin] Data Binding

[Anton Minashkin] Data Binding

Presentation from GDG DevFest Ukraine 2015 - the biggest Google related event in the country. October 23-24, Lviv. Learn more at http://devfest.gdg.org.ua/

Google Developers Group Lviv

October 24, 2015
Tweet

More Decks by Google Developers Group Lviv

Other Decks in Programming

Transcript

  1. #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
  2. #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
  3. #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
  4. #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
  5. #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
  6. #dfua Add behavior private void attemptLogin() { String email =

    mEmailView.getText().toString(); String password = mPasswordView.getText().toString(); doLogin(email, password); } } LoginActivity.java
  7. #dfua (View) Model public class LoginForm { private String mLogin

    = "login"; private String mPassword = "password"; ... //getXXX & setXXX ... public void doLogin() { ... } } LoginForm.java
  8. #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
  9. #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
  10. #dfua Layout + Data Binding public class LoginForm extends BaseObservable

    { private String mLogin = "login"; private String mPassword = "password"; public void doLogin(View v) { ... } } LoginForm.java
  11. #dfua Layout + Data Binding public class LoginForm extends BaseObservable

    { ... @Bindable public String getPassword() { return mPassword; } @Bindable public String getLogin() { return mLogin; } ... } LoginForm.java
  12. #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
  13. #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
  14. #dfua Layout + Data Binding public interface UpdateText { void

    updateText(String s); } UpdateText.java
  15. #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
  16. #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
  17. #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
  18. #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
  19. #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
  20. #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 ?:
  21. #dfua Expression language. Commons android:text="@{String.valueOf(index + 1)}" android:visibility="@{age > 13

    ? View.GONE : View.VISIBLE}" android:transitionName='@{"image_" + id}' layout.xml
  22. #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
  23. #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
  24. #dfua Observable objects • Should implement Observable • ...or extend

    BaseObservable • Should call notifyPropertyChanged(...) when modified • Should use @Bindable for fields/getters
  25. #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
  26. #dfua ObservableFields Base class ObservableField Siblings: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort,

    ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable, ObservableField<T>
  27. #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
  28. #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
  29. #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
  30. #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
  31. #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
  32. #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
  33. #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
  34. #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
  35. #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
  36. #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
  37. #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
  38. #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
  39. #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
  40. #dfua Summary • MVVM • Less code • More Value

    • Easy to test (Unit tests, Unit test, Unit test!) • API Level 7+ • Works like Magic