Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Android data binding

4,432 views

Published on

Speech about Android Data Binding in Mobiconf 2015 (Krakow)

Published in: Technology

Android data binding

  1. 1. Android data binding The rules of the game have changed
  2. 2. 20 yrs tinkering with computers A lot of time on software localization On Android since 2010 (Cupcake) Mobile R+D Lead at Worldine Iberia Android GDE (Google Developer Expert) I love making UI Proud parent of a 8 years old OS fan @sergiandreplace sergiandreplace.com sergi.Martinez[at]gmail.com About me – Sergi Martínez
  3. 3. Android data binding Introduced by Google in I/O 2015 (almost unnoticed) But really important. It will change the way we make UIs
  4. 4. Google dixit Writing declarative layouts and minimize the glue code necessary to bind your application logic and layouts. Data Binding library is for...
  5. 5. What is data binding? Data binding is the process that establishes a connection between the application UI (User Interface) and Business logic. If the settings and notifications are correctly set, the data reflects changes when made. It can also mean that when the UI is changed, the underlying data will reflect that change Wikipedia – Data binding
  6. 6. But before… Let’s talk about inflation…
  7. 7. What’s inflation? Inflation is the process used by Android to transform XML layouts into a tree of View objects.
  8. 8. z Inflation process Inflate as Or also performed inside setContentView LayoutInflater.from(this).inflate(R.layout.activity_main, rootView); public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
  9. 9. Steps on inflation 1. The inflater parses the xml file 2. The inflater tries to create an object as: a. android.widget.<tag> b. android.webkit.<tag> c. <tag> 3. If succeds: creates the objects and sets the right properties If fails: hell on earth
  10. 10. z Some code (using custom inflater) New inflater defined as InflaterFactory
  11. 11. z Some code (using custom inflater) New inflater defined as InflaterFactory
  12. 12. z Some code (using custom inflater) Once we set a new InflatorFactory, we are ready for inflation
  13. 13. z More code (hacking the code inflater)
  14. 14. z More code (hacking the code inflater)
  15. 15. z More code (hacking the code inflater)
  16. 16. z More code (hacking the code inflater)
  17. 17. z More code (hacking the code inflater) Custom code
  18. 18. The whole example Check it out on https://github.com/sergiandreplace/AndroidFontInflaterFactory (old Eclipse structure) Also an experiment, use at your own risk
  19. 19. And now… Let’s start with data binding… …but…
  20. 20. WARNING Data binding is in beta state Use at your own risk Could suffer several changes Could have bugs DO NOT USE IN PRODUCTION
  21. 21. Steps to follow 1. Add Data Binding library 2. Apply binding to layout 3. Create data binding object 4. Do the binding
  22. 22. z Adding Data Binding library Project build.gradle App build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } } apply plugin: 'com.android.application' apply plugin: 'com.android.databinding'
  23. 23. z Adding Data Binding library Project build.gradle App build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } } apply plugin: 'com.android.application' apply plugin: 'com.android.databinding'
  24. 24. z apply plugin: 'com.android.application' apply plugin: 'com.android.databinding' Adding Data Binding library Project build.gradle App build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } }
  25. 25. z Adding Data Binding library Project build.gradle App build.gradle …and sync gradle! buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' classpath "com.android.databinding:dataBinder:1.0-rc1" } } apply plugin: 'com.android.application' apply plugin: 'com.android.databinding'
  26. 26. z Apply binding to layout Before <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
  27. 27. z Apply binding to layout After <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="data" type="com.sergiandreplace.hellodatabinding.ViewData" /> </data> <RelativeLayout xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=“@{data.helloMessage}" /> </RelativeLayout> </layout>
  28. 28. z Apply binding to layout New root tag <layout> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="data" type="com.sergiandreplace.hellodatabinding.ViewData" /> </data> <RelativeLayout xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=“@{data.helloMessage}" /> </RelativeLayout> </layout>
  29. 29. z Apply binding to layout Two parts: data and layout itself <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="data" type="com.sergiandreplace.hellodatabinding.ViewData" /> </data> <RelativeLayout xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=“@{data.helloMessage}" /> </RelativeLayout> </layout>
  30. 30. z Apply binding to layout Name of object to be injected and type of the object <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="data" type="com.sergiandreplace.hellodatabinding.ViewData" /> </data> <RelativeLayout xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=“@{data.helloMessage}" /> </RelativeLayout> </layout>
  31. 31. z Apply binding to layout Binded property of the object <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="data" type="com.sergiandreplace.hellodatabinding.ViewData" /> </data> <RelativeLayout xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=“@{data.helloMessage}" /> </RelativeLayout> </layout>
  32. 32. z Create data binding object This way: Or this way: public class ViewData { public final String helloMessage; public ViewData(String helloMessage) { this.helloMessage = helloMessage; } } public class ViewData { private final String helloMessage; public ViewData(String helloMessage) { this.helloMessage = helloMessage; } public String getHelloMessage() { return helloMessage; } }
  33. 33. z Create data binding object This way: Or this way: public class ViewData { public final String helloMessage; public ViewData(String helloMessage) { this.helloMessage = helloMessage; } } public class ViewData { private final String helloMessage; public ViewData(String helloMessage) { this.helloMessage = helloMessage; } public String getHelloMessage() { return helloMessage; } }
  34. 34. z Create data binding object This way: Or this way: public class ViewData { public final String helloMessage; public ViewData(String helloMessage) { this.helloMessage = helloMessage; } } public class ViewData { private final String helloMessage; public ViewData(String helloMessage) { this.helloMessage = helloMessage; } public String getHelloMessage() { return helloMessage; } }
  35. 35. z Do the binding On the activity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); ViewData data = new ViewData(getString(R.string.hello_world)); binding.setData(data); }
  36. 36. z Do the binding On the activity We create the binding object @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); ViewData data = new ViewData(getString(R.string.hello_world)); binding.setData(data); }
  37. 37. z Do the binding On the activity Layout name Proper cased + Binding (activity_main.xml -> ActivityMainBinding) Generated on compilation. You must launch make before AS can recognize Only worked with canary (1.4 RC3) 1.4 published yesterday (it should work) You must use Java 1.7 as language level @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); ViewData data = new ViewData(getString(R.string.hello_world)); binding.setData(data); } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 }
  38. 38. z Do the binding On the activity Instantiate our ViewData object and set a message @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); ViewData data = new ViewData(getString(R.string.hello_world)); binding.setData(data); }
  39. 39. z Do the binding On the activity Give the data object to the binding for the painting @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); ViewData data = new ViewData(getString(R.string.hello_world)); binding.setData(data); }
  40. 40. Execute… …and it works! Pretty exciting, isn’t it? Not really Let’s see some other things we can do
  41. 41. z Other things to do <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_offer” android:visibility="@{product.isOffer? View.VISIBLE : View.GONE}"/> <data> <import type="android.view.View"/> <variable name=“product” type=“com.sergiandreplace.hellodatabinding.product”/> </data>
  42. 42. z More things to do <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{StringUtils.getFormatCurrency(product.price, product.currency)}” /> <data> <import type="com.sergiandreplace.hellodatabinding.StringUtils"/> <variable name=“product” type=“com.sergiandreplace.hellodatabinding.product”/> </data> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{StringUtils.getFormatCurrency(product.Price) + product.currency}” />
  43. 43. z Include with Binding <?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=“product" type=“com.sergiandreplace.hellodatabinding.Product"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/header" bind:product="@{product}"/> <include layout="@layout/detail" bind:product="@{product}"/> </LinearLayout> </layout> Merge not supported 
  44. 44. Supported operators Mathematical + - / * % String concatenation + Logical && || Binary & | ^ Unary + - ! ~ Shift >> >>> << Comparison == > < >= <= Null ?? (a??b = a==null?b:a) instanceof Grouping () Literals - character, String, numeric, null Cast Method calls Field access Array access [] Ternary operator ?:
  45. 45. z Even list handling! <data> <import type="android.util.SparseArray"/> <import type="java.util.Map"/> <import type="java.util.List"/> <variable name="list" type="List&lt;String>"/> <variable name="sparse" type="SparseArray&lt;String>"/> <variable name="map" type="Map&lt;String, String>"/> <variable name="index" type="int"/> <variable name="key" type="String"/> </data> … android:text="@{list[index]}" … android:text="@{sparse[index]}" … android:text="@{map[key]}"
  46. 46. z Observable objects private static class Product extends BaseObservable { private String name; private String description; @Bindable public String getName() { return this.name; } @Bindable public String getDescription() { return this.description; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); } public void setLastName(String description) { this. description = description; notifyPropertyChanged(BR. description); } }
  47. 47. z Observable objects Extends BaseObservable private static class Product extends BaseObservable { private String name; private String description; @Bindable public String getName() { return this.name; } @Bindable public String getDescription() { return this.description; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); } public void setLastName(String description) { this. description = description; notifyPropertyChanged(BR. description); } }
  48. 48. z Observable objects Declare getters as bindable private static class Product extends BaseObservable { private String name; private String description; @Bindable public String getName() { return this.name; } @Bindable public String getDescription() { return this.description; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); } public void setLastName(String description) { this. description = description; notifyPropertyChanged(BR. description); } }
  49. 49. z Observable objects Notify changes BR is like R for Bindables (aka: magic generated on compilation) private static class Product extends BaseObservable { private String name; private String description; @Bindable public String getName() { return this.name; } @Bindable public String getDescription() { return this.description; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); } public void setLastName(String description) { this. description = description; notifyPropertyChanged(BR.description); } }
  50. 50. z Even easier: observable fields private static class Product{ public final ObservableField<String> name = new ObservableField<>(); public final ObservableField<String> description = new ObservableField<>(); public final ObservableInt stock = new ObservableInt(); }
  51. 51. z Even easier: observable fields ObservableField just uses generics for any class private static class Product{ public final ObservableField<String> name = new ObservableField<>(); public final ObservableField<String> description = new ObservableField<>(); public final ObservableInt stock = new ObservableInt(); }
  52. 52. z Even easier: observable fields ObservableInt, ObservableLong, ObservableParcelable, etc, already usable private static class Product{ public final ObservableField<String> name = new ObservableField<>(); public final ObservableField<String> description = new ObservableField<>(); public final ObservableInt stock = new ObservableInt(); }
  53. 53. z Even easier: observable fields To use them… private static class Product{ public final ObservableField<String> name = new ObservableField<>(); public final ObservableField<String> description = new ObservableField<>(); public final ObservableInt stock = new ObservableInt(); } Product.stock.get(); product.name.set(“Biscuits”);
  54. 54. Attribute setters Binding library tries to match the attribute setter with attribute name Ex: on android:text=“@{…}” it looks for the setText method In some cases we want something more accurated We can create our own attribute setters
  55. 55. z Attribute Setters @BindingAdapter("android:paddingLeft") public static void setPaddingLeft(View view, int padding) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); }
  56. 56. Attribute setters Not available for custom namespaces Multiple parameters available @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); } <ImageView app:imageUrl=“@{venue.imageUrl}” app:error=“@{@drawable/venueError}”/>
  57. 57. There is even more Converters Arrays and lists handling Messing up with lists ViewStubs! Dynamic variables
  58. 58. But enough for today We are all discovering it and learning what can be done Play around with it Check articles of really cool people on the Internet
  59. 59. For last… Let’s talk a bit about architectures • MVC – Model-View-Controller • MVP – Model-View-Presenter • MVVM – Model-View-ViewModel
  60. 60. Basic comparison From Geeks with blog (geekswithblogs.net)
  61. 61. Final big advice Do not put business logic in the View Model CLEARLY separate business-logic and representation-logic <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/discount” android:visibility="@{product.isOffer? 0.15 : 0}"/>
  62. 62. Final big advice Do not put business logic in the View Model CLEARLY separate business-logic and representation-logic <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/discount” android:visibility="@{product.isOffer? 0.15 : 0}"/>
  63. 63. Q A uestions nswers
  64. 64. 20 yrs tinkering with computers A lot of time on software localization On Android since 2010 (Cupcake) Mobile R+D Lead at Worldine Iberia Android GDE (Google Developer Expert) I love making UI Proud parent of a 8 years old OS fan @sergiandreplace sergiandreplace.com sergi.Martinez[at]gmail.com About me – Sergi Martínez

×