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


0ebcda68732e9ed18d903d34bcf62b64?s=47 Lisa Wray
February 09, 2016


A tour through the data binding framework's obvious and not-so-obvious perks. Reduce boilerplate, avoid NullPointerExceptions, decrease code complexity, and maybe even fix some Android pet peeves.


Lisa Wray

February 09, 2016

More Decks by Lisa Wray

Other Decks in Programming


  1. “@{dataBinding}” talk:title= @{dataBinding} @lisawrayz

  2. textView.setCompoundDrawablesWithIntrinsicBounds( ContextCompat.getDrawable(this, R.drawable.cat), null, null, null); Problem: Repetitive Java boilerplate

    @{dataBinding} findViewById, casts setters are verbose/confusing toolbar = (Toolbar) findViewById(R.id.toolbar);
  3. Problem: Repetitive Java boilerplate @{dataBinding} findViewById, casts setters are verbose/confusing

    XML layout is limited Manually keep track of UI updates
  4. What is it? @{dataBinding} A framework to connect your model

    and your UI Once or persistently
  5. An XML attribute for every Java setter @{dataBinding} What else

    is it?
  6. Custom XML attributes @{dataBinding} What else is it?

  7. Overwrite Android XML attributes @{dataBinding} What else is it?

  8. An alternative to custom views @{dataBinding} What else is it?

  9. O.K., show me!

  10. Find the views Set custom font Set button colors Load

    and set the image Set title
  11. Before: inflate and find views CollapsingToolbarLayout appBarLayout = (CollapsingToolbarLayout) findViewById(R.id.toolbar_layout);

    ImageView backdropImageView = (ImageView) findViewById(R.id.backdrop); Button upvoteButton = (Button) findViewById(R.id.upvote); Button downvoteButton = (Button) findViewById(R.id.downvote); setContentView(R.layout.activity_pet_detail); After PetDetailBinding binding = DataBindingUtil.setContentView (this, R.layout.pet_detail);
  12. Before:Java if (pet != null) { appBarLayout.setTitle(pet.getName()); } After:XML <android.support.design.widget.CollapsingToolbarLayout

    app:title="@{pet.name}" >
  13. Before: Java Typeface lobster = FontCache.getInstance().get("LobsterTwo-Bold"); appBarLayout.setCollapsedTitleTypeface(lobster); appBarLayout.setExpandedTitleTypeface(lobster); After:XML <android.support.design.widget.CollapsingToolbarLayout

    app:collapsedTitleTypeface="@{`LobsterTwo-Bold`}" app:expandedTitleTypeface=“@{`LobsterTwo-Bold`}" >
  14. <Button app:selected=“@{vote == VOTE.UPVOTE}" android:tint=“@drawable/upvote_selector” /> Before:Java After:XML switch(pet.vote) {

    case UPVOTE: upvoteButton.setSelected(true); downvoteButton.setSelected(false); break; case DOWNVOTE: …
  15. Before: Java Glide.with(this).load(pet.getImageUrl()).into(backdropImageView); After:XML <ImageView app:imageUrl="@{pet.imageUrl}"/>

  16. Making the connection

  17. PetDetailBinding binding = DataBindingUtil.setContentView (this, R.layout.pet_detail); Before: Java … <layout>

    <data> <variable name="pet" type="com.xwray.dogmeetscat.Pet"/> </data> After:XML </layout> binding.setPet(pet); PetDetailBinding binding = DataBindingUtil.setContentView (this, R.layout.pet_detail); Your old layout goes here Your model object
  18. 100% generated Java code Uses bitwise flags to mark ‘dirty’

    One traversal to find all views How does it work? @{dataBinding}
  19. layout/pet.xml generated: PetBinding.java PetBinding.image .title .upvote @{dataBinding}

  20. @{ }

  21. Existing attributes Pet.getName() app:title="@{pet.name}"

  22. android:text android:textColor Existing attributes android:drawableLeft android:src … and many, many

  23. <Button app:selected=“@{vote == VOTE.UPVOTE}" android:tint=“@drawable/upvote_selector” /> Attributes for every Java

    setter View.setSelected()
  24. app:imageUrl="@{pet.imageUrl}" Custom attributes

  25. @BindingAdapter({"bind:imageUrl"}) public static void loadImage(ImageView view, String url) { Glide.with(view.getContext())

    .load(url) .into(view); } Bindings You pick The view you’re binding Attribute
  26. app:font Custom attributes @BindingAdapter({"bind:font"}) public static void setFont(TextView textView, String

    fontName) { Typeface type = FontCache.getInstance().get(fontName); textView.setTypeface(type); } Bindings Tinkerbell
  27. app:collapsedTitleTypeface="@{`LobsterTwo-Bold`}" app:expandedTitleTypeface="@{`LobsterTwo-Bold`}" Custom attributes @BindingAdapter("bind:expandedTitleTypeface") public static void setExpandedTitleTypeface( CollapsingToolbarLayout

    layout, String fontName) { Typeface type = FontCache.getInstance().get(fontName); layout.setExpandedTitleTypeface(type); } @BindingAdapter("bind:collapsedTitleTypeface") public static void setCollapsedTitleTypeface …
  28. <TextView android:drawableRight=“@{isCat ? @drawable/cat : @drawable/dog}” /> <View android:paddingRight=“@{2 *

    @dimen/margin}” /> <View android:paddingRight=“@{@dimen/margin + @dimen/image_width}” /> Evaluate simple expressions app:selected=“@{vote == VOTE.UPVOTE}"
  29. before: if (pet != null) { appBarLayout.setTitle(pet.getName()); } after: android:text=“@{pet.name}”

    Avoid NPEs android:text=“@{pet.name.last}”
  30. @BindingAdapter("android:indeterminateTint") public static void setIndeterminateTint( ProgressBar progressBar, int color) {

    Drawable toTint = progressBar.getIndeterminateDrawable().mutate(); toTint.setColorFilter(color, PorterDuff.Mode.SRC_IN); } Overwrite Android attributes <ProgressBar style="?android:attr/progressBarStyle" android:indeterminateTint="@{@color/pink}" />
  31. layout/family.xml <layout> … <include layout="@layout/pet" app:pet=“@{family.pet}" /> </layout> <include> layout/pet.xml

    <layout> <data> <variable name="pet" type="com.xwray.dogmeetscat.Pet"/> </data> … </layout>
  32. One way binding Model changes, view is updated Persistent binding

  33. enum VOTE { UPVOTE, DOWNVOTE, NONE } public class VoteState

    { public final ObservableField<VOTE> vote = new ObservableField(); } voteState.vote.set(VOTE.DOWNVOTE) Persistent binding
  34. enum VOTE { UPVOTE, DOWNVOTE, NONE } public class VoteState

    extends BaseObservable { private VOTE vote; @Bindable getVote(); setVote(VOTE vote) { this.vote = vote; notifyChanged(BR.vote) } } Persistent binding
  35. “In beta”, you said “It’ll be fun”, you said

  36. Gradle integration Syntax highlighting Code completion (2.0.0-alpha5) View and debug

    generated code Android Studio and You
  37. Refactoring “Convert to data binding” shortcut “Clean project” required sometimes

    Still to come …
  38. Android Studio tips <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> tools:text=“Jane Doe” tools:ignore="UnusedAttribute"

    Declare namespaces in layout tag Use tools: prefix for layout preview Ignore lint warnings
  39. app/build.gradle android { dataBinding { enabled = true } }

    How do I get started?
  40. fonts: goo.gl/n6lQY7 docs: goo.gl/47cVzB @lisawrayz