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

The Data Binding Library

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

The Data Binding Library

Presentation of the Data Binding Library by Benoît Quenaudon

Demo repo: https://github.com/oldergod/DataBindingDemo
Video: https://www.youtube.com/watch?v=411jp1ceiH8

Avatar for Benoît Quenaudon

Benoît Quenaudon

November 27, 2016
Tweet

More Decks by Benoît Quenaudon

Other Decks in Programming

Transcript

  1. Problem with Android • Setters are complicated and verbose binding.date.setCompoundDrawablesWithIntrinsicBounds(

      ContextCompat.getDrawable(this, R.drawable.ic_giants), null, null, null);
  2. Problem with Android • Manually keep track of UI updates

    textView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged() {} @Override public void onTextChanged() {} @Override public void afterTextChanged() {} });
  3. Problem with Android • Not all setters in Java have

    XML equivalent textView.setTypeface(); drawerLayout.setScrimColor();
  4. Data Binding Library ? • A framework to connect your

    UI and model ◦ Once or persistently • One XML attribute for every Java setter • Custom XML attributes • Can override android:’s XML attributes
  5. Data Binding Library ? • A framework to connect your

    UI and model ◦ Once or persistently • One XML attribute for every Java setter • Custom XML attributes • Can override android:’s XML attributes
  6. Data Binding Library ? • A framework to connect your

    UI and model ◦ Once or persistently • One XML attribute for every Java setter • Custom XML attributes • Can override android:’s XML attributes
  7. Data Binding Library ? • A framework to connect your

    UI and model ◦ Once or persistently • One XML attribute for every Java setter • Custom XML attributes • Can override android:’s XML attributes
  8. Data Binding Library ? • A framework to connect your

    UI and model ◦ Once or persistently • One XML attribute for every Java setter • Custom XML attributes • Can override android:’s XML attributes
  9. match.xml <android.support.constraint.ConstraintLayout> <TextView android:id="@+id/date" /> <TextView android:id="@+id/stadium" /> <include android:id="@+id/homeTeam"

    layout="@layout/team" /> <include android:id="@+id/awayTeam" layout="@layout/team" /> <CheckBox android:id="@+id/showScore" /> <TextView android:id="@+id/score" /> <android.support.design.widget.BottomNavigationView /> </android.support.constraint.ConstraintLayout>
  10. match.xml <android.support.constraint.ConstraintLayout> <TextView android:id="@+id/date" /> <TextView android:id="@+id/stadium" /> <include android:id="@+id/homeTeam"

    layout="@layout/team" /> <include android:id="@+id/awayTeam" layout="@layout/team" /> <CheckBox android:id="@+id/showScore" /> <TextView android:id="@+id/score" /> <android.support.design.widget.BottomNavigationView /> </android.support.constraint.ConstraintLayout>
  11. match.xml <android.support.constraint.ConstraintLayout> <TextView android:id="@+id/date" /> <TextView android:id="@+id/stadium" /> <include android:id="@+id/homeTeam"

    layout="@layout/team" /> <include android:id="@+id/awayTeam" layout="@layout/team" /> <CheckBox android:id="@+id/showScore" /> <TextView android:id="@+id/score" /> <android.support.design.widget.BottomNavigationView /> </android.support.constraint.ConstraintLayout>
  12. match.xml <android.support.constraint.ConstraintLayout> <TextView android:id="@+id/date" /> <TextView android:id="@+id/stadium" /> <include android:id="@+id/homeTeam"

    layout="@layout/team" /> <include android:id="@+id/awayTeam" layout="@layout/team" /> <CheckBox android:id="@+id/showScore" /> <TextView android:id="@+id/score" /> <android.support.design.widget.BottomNavigationView /> </android.support.constraint.ConstraintLayout>
  13. match.xml <android.support.constraint.ConstraintLayout> <TextView android:id="@+id/date" /> <TextView android:id="@+id/stadium" /> <include android:id="@+id/homeTeam"

    layout="@layout/team" /> <include android:id="@+id/awayTeam" layout="@layout/team" /> <CheckBox android:id="@+id/showScore" /> <TextView android:id="@+id/score" /> <android.support.design.widget.BottomNavigationView /> </android.support.constraint.ConstraintLayout>
  14. match.xml <android.support.constraint.ConstraintLayout> <TextView android:id="@+id/date" /> <TextView android:id="@+id/stadium" /> <include android:id="@+id/homeTeam"

    layout="@layout/team" /> <include android:id="@+id/awayTeam" layout="@layout/team" /> <CheckBox android:id="@+id/showScore" /> <TextView android:id="@+id/score" /> <android.support.design.widget.BottomNavigationView /> </android.support.constraint.ConstraintLayout>
  15. Before: XML <?xml version="1.0" encoding="utf-8"?> <LinearLayout> <!----> </LinearLayout> After: XML

    <?xml version="1.0" encoding="utf-8"?> <layout> <LinearLayout> <!----> </LinearLayout> </layout>
  16. Before: XML <?xml version="1.0" encoding="utf-8"?> <LinearLayout> <!----> </LinearLayout> After: XML

    <?xml version="1.0" encoding="utf-8"?> <layout> <LinearLayout> <!----> </LinearLayout> </layout>
  17. Before setContentView(R.layout.activity_main); activityList = (ConstraintLayout) findViewById(R.id.activity_list); dateView = (TextView) findViewById(R.id.date);

    stadiumView = (TextView) findViewById(R.id.stadium); showScoreView = (CheckBox) findViewById(R.id.showScore); scoreView = (TextView) findViewById(R.id.score); bottomNavigationView = (BottomNavigationView)   findViewById(R.id.bottom_navigation); View homeTeam = findViewById(R.id.homeTeam); homeTeamIconView = (ImageView) homeTeam.findViewById(R.id.teamicon); homeTeamNameView = (TextView) homeTeam.findViewById(R.id.teamName); View awayTeam = findViewById(R.id.awayTeam); M O R E
  18. Before: Java if (match.getStadium() != null) { stadiumView.setText(match.getStadium()); } else

    { stadiumView.setText(R.string.unknown_stadium); } After: XML <TextView android:text="@{matchVM.match.stadium ?? @string/unknown_stadium}" />
  19. Before: Java if (match.getStadium() != null) { stadiumView.setText(match.getStadium()); } else

    { stadiumView.setText(R.string.unknown_stadium); } After: XML <TextView android:text="@{matchVM.match.stadium ?? @string/unknown_stadium}" />
  20. Before: Java if (match.getStadium() != null) { stadiumView.setText(match.getStadium()); } else

    { stadiumView.setText(R.string.unknown_stadium); } After: XML <TextView android:text="@{matchVM.match.stadium ?? @string/unknown_stadium}" />
  21. Before: Java <string name="year_date">%1$d年%2$d月%3$d日</string> dateView.setText( getString( R.string.year_date, match.getYear(), match.getMonth(), match.getDay()

    ) ); After: XML <TextView android:text="@{@string/year_date(matchVM.match.year, matchVM.match.month, matchVM.match.day)}" />
  22. Before: Java <string name="year_date">%1$d年%2$d月%3$d日</string> dateView.setText( getString( R.string.year_date, match.getYear(), match.getMonth(), match.getDay()

    ) ); After: XML <TextView android:text="@{@string/year_date(matchVM.match.year, matchVM.match.month, matchVM.match.day)}" />
  23. Before: Java <string name="year_date">%1$d年%2$d月%3$d日</string> dateView.setText( getString( R.string.year_date, match.getYear(), match.getMonth(), match.getDay()

    ) ); After: XML <TextView android:text="@{@string/year_date(matchVM.match.year, matchVM.match.month, matchVM.match.day)}" />
  24. Before: Java scoreView.setVisibility(match.isShowScore() ? VISIBLE : GONE); @Override public void

    onCheckedChanged(CompoundButton compoundButton, boolean b) { scoreView.setVisibility(b ? VISIBLE : GONE); } After: XML <TextView android:visibility="@{matchVM.match.showScore ? View.VISIBLE : View.GONE}" />
  25. Before: Java scoreView.setVisibility(match.isShowScore() ? VISIBLE : GONE); @Override public void

    onCheckedChanged(CompoundButton compoundButton, boolean b) { scoreView.setVisibility(b ? VISIBLE : GONE); } After: XML <CheckBox android:id="@+id/showScore" /> <TextView android:visibility="@{matchVM.match.showScore ? View.VISIBLE : View.GONE}" />
  26. Before: Java scoreView.setVisibility(match.isShowScore() ? VISIBLE : GONE); @Override public void

    onCheckedChanged(CompoundButton compoundButton, boolean b) { scoreView.setVisibility(b ? VISIBLE : GONE); } After: XML <TextView android:visibility="@{showScore.checked ? View.VISIBLE : View.GONE}" /> <CheckBox android:id="@+id/showScore" />
  27. Before: Java scoreView.setVisibility(match.isShowScore() ? VISIBLE : GONE); @Override public void

    onCheckedChanged(CompoundButton compoundButton, boolean b) { scoreView.setVisibility(b ? VISIBLE : GONE); } After: XML <TextView android:visibility="@{showScore.checked ? View.VISIBLE : View.GONE}" /> <CheckBox android:id="@+id/showScore" />
  28. Before: Java scoreView.setVisibility(match.isShowScore() ? VISIBLE : GONE); @Override public void

    onCheckedChanged(CompoundButton compoundButton, boolean b) { scoreView.setVisibility(b ? VISIBLE : GONE); } After: XML <TextView android:visibility="@{showScore.checked ? View.VISIBLE : View.GONE}" />
  29. Before: Java bottomNavigationView.setOnNavigationItemSelectedListener(this); @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) {}

    After: XML <BottomNavigationView app:onNavigationItemSelectedListener="@{handler::onNavigationClick}" />
  30. Before: Java bottomNavigationView.setOnNavigationItemSelectedListener(this); @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) {}

    After: XML <BottomNavigationView app:onNavigationItemSelectedListener="@{handler::onNavigationClick}" />
  31. After: XML <layout> <data> <variable name="matchVM" type="class.path.MatchViewModel" /> <variable name="handler"

    type="class.path.ListActivity" /> </data> <!--old layout--> </layout> After: Java ActivityMainBinding binding =   DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setMatchVM(matchViewModel); binding.setHandler(this);
  32. After: XML <layout> <data> <variable name="matchVM" type="class.path.MatchViewModel" /> <variable name="handler"

    type="class.path.ListActivity" /> </data> <!--old layout--> </layout> After: Java ActivityMainBinding binding =   DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setMatchVM(matchViewModel); binding.setHandler(this);
  33. After: XML <layout> <data> <variable name="matchVM" type="class.path.MatchViewModel" /> <variable name="handler"

    type="class.path.ListActivity" /> </data> <!--old layout--> </layout> After: Java ActivityMainBinding binding =   DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setMatchVM(matchViewModel); binding.setHandler(this);
  34. After: XML <layout> <data> <variable name="matchVM" type="class.path.MatchViewModel" /> <variable name="handler"

    type="class.path.ListActivity" /> </data> <!--old layout--> </layout> After: Java ActivityMainBinding binding =   DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setMatchVM(matchViewModel); binding.setHandler(this);
  35. After: XML <layout> <data> <variable name="team" type="class.path.Team" /> </data> ...

    </layout> team.xml <layout> … <include layout="@layout/team" app:team="@{matchVM.match.homeTeam}" /> </layout> match.xml
  36. After: XML <layout> <data> <variable name="team" type="class.path.Team" /> </data> ...

    </layout> team.xml <layout> … <include layout="@layout/team" app:team="@{matchVM.match.homeTeam}" /> </layout> match.xml
  37. After: XML <layout> <data> <variable name="team" type="class.path.Team" /> </data> ...

    </layout> team.xml <layout> … <include layout="@layout/team" app:team="@{matchVM.match.homeTeam}" /> </layout> match.xml
  38. ViewModel public class MatchViewModel { private Match match; public Match

    getMatch() { return match; } public void setMatch(Match match) { this.match = match; } }
  39. ViewModel public class MatchViewModel extends BaseObservable { private Match match;

    @Bindable public Match getMatch() { return match; } public void setMatch(Match match) { this.match = match; notifyPropertyChanged(BR.match); } }
  40. ViewModel public class MatchViewModel extends BaseObservable { private Match match;

    @Bindable public Match getMatch() { return match; } public void setMatch(Match match) { this.match = match; notifyPropertyChanged(BR.match); } }
  41. ViewModel public class MatchViewModel extends BaseObservable { private Match match;

    @Bindable public Match getMatch() { return match; } public void setMatch(Match match) { this.match = match; notifyPropertyChanged(BR.match); } }
  42. ViewModel public class MatchViewModel extends BaseObservable { private Match match;

    @Bindable public Match getMatch() { return match; } public void setMatch(Match match) { this.match = match; notifyPropertyChanged(BR.match); } }
  43. Two way Binding: Model ↔ View ModelView changes ⇒ UI

    updates ModelView updates ⇐ UI changes
  44. Two way Binding: Model ↔ View ModelView changes ⇒ UI

    updates ModelView updates ⇐ UI changes
  45. Data Binding Library: How ? • Zero reflection • 100%

    generated Java code • Bitwise flags to make views dirty
  46. Data Binding Library: How ? • Zero reflection • 100%

    generated Java code • Bitwise flags to make views dirty
  47. Data Binding Library: How ? • Zero reflection • 100%

    generated Java code • Bitwise flags to make views dirty
  48. Data Binding Library: How ? • Zero reflection • 100%

    generated Java code • Bitwise flags to make views dirty
  49. Data Binding Library: Generated Code • from layout/match.xml • MatchBinding.java

    • matchBinding.score ◦ MatchBinding.date ◦ MatchBinding.team ◦ MatchBinding.showScore ◦ MatchBinding.bottomNavigationView
  50. Attributes for every java setter class Team { private int

    drawableId; public int getDrawableId() {} } <ImageView app:imageResource="@{team.drawableId}" /> class ImageView > void setImageResource (int resId)
  51. Attributes for every java setter class Team { private int

    drawableId; public int getDrawableId() {} } <ImageView app:imageResource="@{team.drawableId}" /> class ImageView > void setImageResource (int resId)
  52. Custom XML Attributes <ImageView app:imageUrl="@{team.imageUrl}" /> @BindingAdapter("imageUrl") public static void

    loadImage(ImageView view, String url) { Picasso.with(view.getContext()) .load(url) .into(view); }
  53. Custom XML Attributes <ImageView app:imageUrl="@{team.imageUrl}" /> @BindingAdapter("imageUrl") public static void

    loadImage(ImageView view, String url) { Picasso.with(view.getContext()) .load(url) .into(view); }
  54. Java Code Evaluation android:visibility="@{showScore.checked ? View.VISIBLE : View.GONE}" android:padding="@{@dimen/activity_vertical_margin /

    2}" android:drawableLeft="@{isCat ? @drawable.cat : @drawable.dog}" android:onClick="@{() -> presenter.onSaveClick(task)}"
  55. Null Pointer Exception さようなら if (match != null && match.getHomeTeam()

    != null) { homeTeamNameView.setText(match.getHomeTeam().getFullname()); }
  56. Null Pointer Exception さようなら if (match != null && match.getHomeTeam()

    != null) { homeTeamNameView.setText(match.getHomeTeam().getFullname()); } android:text="@{match.team.fullname}"
  57. Android Studio • Gradle integration • Syntax highlighting • Code

    completion • Can view/debug generated code
  58. Android Studio • Gradle integration • Syntax highlighting • Code

    completion • Can view/debug generated code
  59. Android Studio • Gradle integration • Syntax highlighting • Code

    completion • Can view/debug generated code
  60. Android Studio • Gradle integration • Syntax highlighting • Code

    completion • Can view/debug generated code
  61. Android Studio • Gradle integration • Syntax highlighting • Code

    completion • Can view/debug generated code
  62. Android Studio Tips • Put namespaces in <layout> <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"> <LinearLayout> <!----> </LinearLayout> </layout>
  63. Android Studio Tips • Use tools: for preview <TextView tools:text="甲子園"

    /> <ImageView tools:src="@drawable/image" /> <View tools:visibility="visible" />
  64. Easy to start • Can be applied to a unique

    part of your app • Don’t have to use every feature ◦ Only view binding, ◦ One way data binding, ◦ Custom XML attributes...
  65. Want some code? Demo App • https://github.com/oldergod/DataBindingDemo ◦ 0-no-databinding ◦

    1-minimal-setup ◦ 2-viewbinding ◦ 3-oneway-data-binding ◦ 4-view-binding-expression ◦ 5-binding-adapters ◦ 6-persistent-data-binding ◦ 7-event-listeners ◦ 8-twoway-data-binding
  66. References • DataBinding Demo App ◦ https://github.com/oldergod/DataBindingDemo • Data Bindling

    Library ◦ https://developer.android.com/topic/libraries/data-binding/index.html • talk:title=”@{databinding}” ◦ https://www.youtube.com/watch?v=zYGVsTE_scI • 057: Data Binding with GDE Lisa Wray ◦ http://fragmentedpodcast.com/episodes/057/ • George Mount’s blog posts ◦ https://medium.com/@georgemount007