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

talk:title="@{dataBinding}

Lisa Wray
February 09, 2016

 talk:title="@{dataBinding}

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
Tweet

More Decks by Lisa Wray

Other Decks in Programming

Transcript

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

    View Slide

  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);

    View Slide

  3. Problem:
    Repetitive Java boilerplate
    @{dataBinding}
    findViewById, casts
    setters are verbose/confusing
    XML layout is limited
    Manually keep track of UI updates

    View Slide

  4. What is it?
    @{dataBinding}
    A framework to connect your
    model and your UI
    Once or persistently

    View Slide

  5. An XML attribute for every Java setter
    @{dataBinding}
    What else is it?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  9. O.K., show me!

    View Slide

  10. Find the views
    Set custom
    font
    Set button
    colors
    Load and set
    the image
    Set title

    View Slide

  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);

    View Slide

  12. Before:Java
    if (pet != null) {
    appBarLayout.setTitle(pet.getName());
    }
    After:XML
    app:title="@{pet.name}"
    >

    View Slide

  13. Before: Java
    Typeface lobster = FontCache.getInstance().get("LobsterTwo-Bold");
    appBarLayout.setCollapsedTitleTypeface(lobster);
    appBarLayout.setExpandedTitleTypeface(lobster);
    After:XML
    app:collapsedTitleTypeface="@{`LobsterTwo-Bold`}"
    app:expandedTitleTypeface=“@{`LobsterTwo-Bold`}"
    >

    View Slide

  14. 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:

    View Slide

  15. Before: Java
    Glide.with(this).load(pet.getImageUrl()).into(backdropImageView);
    After:XML

    View Slide

  16. Making the connection

    View Slide

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



    name="pet" type="com.xwray.dogmeetscat.Pet"/>

    After:XML

    binding.setPet(pet);
    PetDetailBinding binding = DataBindingUtil.setContentView
    (this, R.layout.pet_detail);
    Your old layout
    goes here
    Your model
    object

    View Slide

  18. 100% generated Java code
    Uses bitwise flags to mark ‘dirty’
    One traversal to find all views
    How does it work?
    @{dataBinding}

    View Slide

  19. layout/pet.xml
    generated: PetBinding.java
    PetBinding.image
    .title
    .upvote
    @{dataBinding}

    View Slide

  20. @{ }

    View Slide

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

    View Slide

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

    View Slide

  23. app:selected=“@{vote == VOTE.UPVOTE}"
    android:tint=“@drawable/upvote_selector”
    />
    Attributes for every Java setter
    View.setSelected()

    View Slide

  24. app:imageUrl="@{pet.imageUrl}"
    Custom attributes

    View Slide

  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

    View Slide

  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

    View Slide

  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 …

    View Slide

  28. android:drawableRight=“@{isCat ? @drawable/cat : @drawable/dog}”
    />
    android:paddingRight=“@{2 * @dimen/margin}”
    />
    android:paddingRight=“@{@dimen/margin + @dimen/image_width}”
    />
    Evaluate simple expressions
    app:selected=“@{vote == VOTE.UPVOTE}"

    View Slide

  29. before:
    if (pet != null) {
    appBarLayout.setTitle(pet.getName());
    }
    after:
    android:text=“@{pet.name}”
    Avoid NPEs
    android:text=“@{pet.name.last}”

    View Slide

  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
    style="?android:attr/progressBarStyle"
    android:indeterminateTint="@{@color/pink}"
    />

    View Slide

  31. layout/family.xml


    layout="@layout/pet"
    app:pet=“@{family.pet}" />


    layout/pet.xml






    View Slide

  32. One way binding
    Model changes, view is updated
    Persistent binding

    View Slide

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

    View Slide

  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

    View Slide

  35. “In beta”, you said
    “It’ll be fun”, you said

    View Slide

  36. Gradle integration
    Syntax highlighting
    Code completion (2.0.0-alpha5)
    View and debug generated code
    Android Studio and You

    View Slide

  37. Refactoring
    “Convert to data binding” shortcut
    “Clean project” required sometimes
    Still to come …

    View Slide

  38. Android Studio tips
    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

    View Slide

  39. app/build.gradle
    android {
    dataBinding {
    enabled = true
    }
    }
    How do I get started?

    View Slide

  40. fonts: goo.gl/n6lQY7
    docs: goo.gl/47cVzB
    @lisawrayz

    View Slide