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

Deep dive into Android Data Binding

Deep dive into Android Data Binding

Deep dive into Android Data Binding talk @ Droidcon Berlin 2016

Radek Piekarz

June 16, 2016
Tweet

More Decks by Radek Piekarz

Other Decks in Programming

Transcript

  1. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  2. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  3. Changes in Activity / Fragment code @Override protected void onCreate(Bundle

    savedInstanceState) { super.onCreate(savedInstanceState); MainActivityBinding binding = DataBindingUtil .setContentView(this, R.layout.main_activity); binding.myId.setText("John Doe") } Type safe!
  4. Binding utils DataBindingUtil.setContentView(activity, layoutId); DataBindingUtil.inflate(inflater, layoutId, parent, attachToParrent); ListItemBinding binding

    = ListItemBinding.bind(viewRoot); Use for activities Use for any view Bind view that was already inflated
  5. Changes in layout file <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data class="CustomClassName"> <variable name="user"

    type="com.example.User"/> </data> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{user.firstName}" /> </layout>
  6. Changes in Activity / Fragment Code @Override protected void onCreate(Bundle

    savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil .setContentView(this, R.layout.main_activity); binding.setUser(new User()); }
  7. Binding expression operators Grouping () Literals character, String, numeric, null

    Method calls, field access Ternary operator ?: Array access [] Null coalescing operator ?? Mathematical + - / * % String concatenation + Logical && || Binary & | ^ Unary + - ! ~ Shift >> >>> << Comparison == > < >= <= instanceof, cast
  8. Notifying view #1 public class User extends BaseObservable { private

    String firstName; public User(String firstName) { this.firstName = firstName; } public void setFirstName(String firstName) { this.firstName = firstName; notifyPropertyChanged(BR.firstName); } @Bindable public String getFirstName() { return this.firstName; } }
  9. Notifying view #2 public class User { public final ObservableField<String>

    firstName; public User(String name) { this.firstName = new ObservableField<>(firstName); } public void setName(String firstName) { this.firstName.set(firstName); } }
  10. Observable fields & collections Observable<T> ObservableBoolean ObservableByte ObservableChar ObservableShort ObservableInt

    ObservableLong ObservableFloat ObservableDouble ObservableParcelable<T> ObservableList<T> ObservableArrayList<T> ObservableMap<K, V> ObservableArrayMap<K, V>
  11. Binding Adapters <layout> <ImageView bind:imageUrl="@{viewModel.someNiceImageUrl}" bind:error="@{@drawable/defaultImage}"/> </layout> @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); }
  12. Binding Adapters @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); }
  13. java.lang.IllegalStateException Required DataBindingComponent is null. If you don't use an

    inflation method taking a DataBindingComponent, use DataBindingUtil.setDefaultComponent or make all BindingAdapter methods static.
  14. Binding Component @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding

    = DataBindingUtil .setContentView(this, R.layout.activity_main, new MyDataBindingCoponent()); binding.setViewModel(new ViewModel()); }
  15. Binding Conversions android:background="@{isError ? @color/red : @color/white}" @BindingConversion public static

    ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color); }
  16. RecyclerView Binding #2 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

    usersViewModel = new UsersViewModel(); usersViewModel.users .add(new SuperUserViewModel(new User("Android", "Dev"))); binding = DataBindingUtil.setContentView(this, R.layout.users_view); binding.setUsersViewModel(usersViewModel); binding.setView(this); }
  17. RecyclerView Binding #3 public class UsersViewModel extends BaseObservable { @Bindable

    public ObservableArrayList<UserViewModel> users; public UsersViewModel() { this.users = new ObservableArrayList<>(); } public void addUser(String name, String surname) { this.users.add(new UserViewModel(new User(name, surname))); } }
  18. RecyclerView Binding #4 public ItemBinder<UserViewModel> itemViewBinder() { return new CompositeItemBinder<UserViewModel>(

    new SuperUserBinder(BR.user, R.layout.item_super_user), new UserBinder(BR.user, R.layout.item_user) ); }
  19. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  20. How it works? Bind ViewModel to View Register for property

    change callbacks Trigger notifyPropertyChanged Request rebind Execute pending bindings User input or from code
  21. How it works? public void setViewModel(TwoWayViewModel viewModel) { updateRegistration(0, viewModel);

    this.mViewModel = viewModel; synchronized(this) { mDirtyFlags |= 0x1L; notifyPropertyChanged(BR.viewModel); super.requestRebind(); }
  22. How it works? @Override protected void executeBindings() { long dirtyFlags

    = 0; synchronized(this) { dirtyFlags = mDirtyFlags; mDirtyFlags = 0; } if ((dirtyFlags & 0x7L) != 0) { if (viewModel != null) { colorViewModel = viewModel.getColor(); } if ((dirtyFlags & 0x7L) != 0) { ColorPickerViewBindings.setColor(this.colorpicker, colorViewModel); EditTextBindings.setText(this.mboundView2, colorViewModel); } if ((dirtyFlags & 0x4L) != 0) { ColorPickerViewBindings.setColorListener(this.colorpicker, null, colorpickercolorAttr); TextViewBindingAdapter.setTextWatcher(this.mboundView2, null, null, null, mboundView2androidTe); this.mboundView3.setOnClickListener(mCallback2); } }
  23. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  24. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  25. Views with Two-Way Binding support • AbsListView -> android:selectedItemPosition •

    CalendarView -> android:date • CompoundButton -> android:checked • DatePicker -> android:year, android:month, android:day • NumberPicker -> android:value • RadioGroup -> android:checkedButton • RatingBar -> android:rating • SeekBar -> android:progres • TabHost -> android:currentTab • TextView -> android:text • TimePicker -> android:hour, android:minute
  26. Two-Way data binding @InverseBindingAdapter(attribute = "color", event = "colorAttrChanged") public

    static int getColor(ColorPickerView view) { return view.getColor(); } attribute + AttrChanged
  27. Activity @BindingAdapter("colorAttrChanged") public static void setColorListener(ColorPickerView view, final InverseBindingListener colorChange)

    { if (colorChange == null) { view.setOnColorChangedListener(null); } else { view.setOnColorChangedListener(new OnColorChangedListener() { @Override public void onColorChanged(int newColor) { colorChange.onChange(); } }); } }
  28. Two-Way data binding @BindingAdapter("color") public static void setColor(ColorPickerView view, int

    color) { if (color != view.getColor()) { view.setColor(color); } } Avoiding cycles
  29. Two-Way data binding public class TwoWayViewModel extends BaseObservable { private

    int color; public void setColor(int color) { this.color = color; this.notifyPropertyChanged(BR.color); } @Bindable public int getColor() { return this.color; } }
  30. Two-Way data binding public class TwoWayBindingActivity extends AppCompatActivity { private

    ActivityTwoWayBinding binding; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_two_way); binding.setViewModel(new TwoWayViewModel()); } }
  31. Two-Way data binding <LinearLayout> <com.github.danielnilsson9.colorpickerview.view.ColorPickerView bind:color="@={viewModel.color}" /> <EditText android:text="@={viewModel.color}" />

    <Button android:text="Set defined color" android:onClick="@{() -> viewModel.setColor(Color.parseColor(`#C97249`))}" /> </LinearLayout>
  32. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  33. Repeated expressions <TextView android:id="@+id/tv_congrats" android:visibility="@{cbShowMore.checked ? View.VISIBLE : View.GONE}" />

    <TextView android:visibility="@{cbShowMore.checked ? View.VISIBLE : View.GONE}" /> <TextView android:visibility="@{cbShowMore.checked ? View.VISIBLE : View.GONE}" />
  34. Repeated expressions <TextView android:id="@+id/tv_congrats" android:visibility="@{cbShowMore.checked ? View.VISIBLE : View.GONE}" />

    <TextView android:visibility="@{tvCongrats.visibility}" /> <TextView android:visibility="@{tvCongrats.visibility}" />
  35. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  36. Dos • From time to time look at generated code

    • Learn from already implemented bindings for framework views • Move view operations to custom bindings as much as possible • Try to use it together with MVVM design pattern • Give it a chance!
  37. Dos • Always check if data binging library will work

    with your other libraries (squidb won’t work )
  38. Don’ts • Don’t reinvent the wheel, on Github there are

    many ready to use bindings • Don’t forget about unit tests!
  39. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  40. MVVM & TDD @Mock ISendService sendService; @Test public void mainViewModel_sendAction_sendService_send()

    { final MainViewModel viewModel = new MainViewModel(sendService); final String givenText = "my text"; viewModel.setTwoWayText(givenText); viewModel.sendAction(); verify(sendService).send(givenText); }
  41. Basics How it works? Lambdas Two-Way data binding New stuff

    announced during Google IO 2016 Dos and don'ts MVVM & TDD Summary
  42. Method count • ~700 methods from databinding library • n

    methods from your custom binding adapters, conversions etc. • k methods from generated code for each layout xml with data binding enabled
  43. Summary Cons Compiler errors are sometimes not saying too much

    Still in beta Documentation is not updated May break other libraries (for example squidb) Pros Easy to start Less boilerplate code Code generation during compilation Easy to integrate with custom views and libraries Really powerful Officialy created and supported by Google Android Team