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

Android Data Binding: from (null) to (data)

Android Data Binding: from (null) to (data)

Android Data Binding library is Google's take on improving the messy, boilerplate riddled layout inflation code that is so common on many Android codebases. This talk will show you how we will be able to use declarative bindings to make populating layouts with data a breeze, and allow data to flow back by using two-way bindings, making UI code more DRY. Also, we will see how to convert old projects incrementally, and the benefits over other libraries like ButterKnife.

https://xrubio.com/talks/talk-android-data-binding-from-null-to-data/

Xavier Rubio Jansana

September 28, 2017
Tweet

More Decks by Xavier Rubio Jansana

Other Decks in Programming

Transcript

  1. A D B ( ) ( ) Xavier Rubio Jansana

     @teknik_tdr  https://xrubio.com  https://github.com/xrubioj/
  2. W ? Standalone library (no additional dependencies) Compatible with API

    7+ (Android 2.1) Announced by Google at I/O 2015 Integrated into Android Studio & Gradle Requires changes to the layouts... simple ones ...but can coexist with old methods → progressive
  3. W ? Declarative layouts Minimize code to bind data to

    layouts Cleaner separation Allows observables (reactive)
  4. H ? In app Gradle file: ...if you use Kotlin

    also add: android { ... dataBinding { enabled = true } } apply plugin: 'kotlin-kapt' ... dependencies { ... kapt "com.android.databinding:compiler:2.3.0" }
  5. L <TextView android:id="@+id/message" android:text="@{model.message}" tools:text="message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginEnd="16dp" android:layout_marginStart="16dp"

    android:layout_marginTop="16dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/> android:id="@+id/message"
  6. A class PojoModelActivity : AppCompatActivity() { lateinit var binding: ActivityPojoModelBinding

    // activity_pojo_model lateinit var model: PojoModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView( this, R.layout.activity_pojo_model) model = PojoModel(message = "Hello World!") binding.model = model } } ActivityPojoModel
  7. M

  8. M Can be as simple as a POJO or data

    class If you try to update this model UI will not update: To update we need to replace the whole model: data class PojoModel(var message: String) binding.model.message = "You will never see this" binding.model = PojoModel("But you will see this")
  9. M More complex like an Observable You can update individual

    fields: class ObservableModel() : BaseObservable() { @get:Bindable var message: String? = null set(message) { field = message notifyPropertyChanged(BR.message) } } @get:Bindable notifyPropertyChanged binding.model.message = "You should see this"
  10. M Middle ground... ObservableFields You can update individual fields: class

    ObservableFieldModel() { val message: ObservableField<String> = ObservableField() val visible: ObservableBoolean = ObservableBoolean() constructor(message: String) : this() { this.message.set(message) } } binding.model.message.set("You should see this") set
  11. B

  12. B Bind variables: in/out Bind views: access views directly Examples

    var binding: ActivityPojoModelBinding binding.model = PojoModel("Hi!") // <variable ...> binding.text.alpha = 0.5f // <TextView android:id="@+id/text" ...>
  13. B Bind activity layout Bind general layouts val binding: ActivityPojoModelBinding

    = DataBindingUtil.setContentView( this, R.layout.activity_pojo_model) // or... val binding: ActivityPojoModelBinding = ActivityPojoModelBinding.inflate(layoutInflater) setContentView(binding.root) var binding: ListItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false) // or... var binding: ListItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // ...and finally retrive layout root View binding.root
  14. V Expressions are not simple references For example, we can

    set visibility like this: Null coalescing operator: Null pointer handling: if model is null android:visibility="@{model.visible ? View.VISIBLE : View.GONE}" android:text='@{"This is the message: " + model.message}' android:text='@{model.message ?? "(no message)"}' // equivalent to Elvis operator ?: android:text='@{model.message}' // no crash, evaluates to "(null)" android:visibility="@{model.visible ? View.VISIBLE : View.GONE}" // false => GONE
  15. O Java-like expressions: Mathematical + - / * % String

    concatenation + Logical && || Binary & | ^ Unary + - ! ~ Shi >> >>> << Comparison == > < >= <= instanceof Grouping () Literals - character, String, numeric, null Cast Method calls Field access Array access [] → Collections android:text="@{list[index]}" Ternary operator ?: Method calls
  16. T

  17. T Allows the binding to update the model For example:

    Needs a setter on the POJO/data class or Observable Model ⚠ ObservableField doesn't work here (weird compilation error ) <EditText android:text="@={model.value}"/> =
  18. C Allows the binding to convert and format data Simplified

    conversion ("hackish") <data> <variable name="model" type="com.xrubio.databindingexample.model.TwoWayDataBin </data> <!-- Layout ... --> <EditText android:text="@={`` + model.value}"/> ``
  19. C Using converters functions <data> <import type="com.xrubio.databindingexample.converters.IntConverter"/> <variable name="model" type="com.xrubio.databindingexample.model.TwoWayDataBindingConversionModel"/>

    </data> <!-- Layout ... --> <EditText android:text="@={IntConverter.INSTANCE.toString(model.value)}"/> IntConverter.INSTANCE.toString object IntConverter { @InverseMethod("toInt") fun toString(value: Int): String { return if (value >= 0) value.toString() else "" } fun toInt(value: String): Int { return try { Integer.parseInt(value) } catch (e: NumberFormatException) { -1 } } } @InverseMethod("toInt")
  20. E

  21. E Method References → Evaluated at compile time <data> <variable

    name="view" type="com.xrubio.databindingexample.ui.MainActivity"/> </data> <!-- Layout ... --> <Button android:text="Button" android:onClick="@{view::onClickButton}"/> fun onClickButton(view: View) { // ... }
  22. E Listener Bindings → Evaluated at run time <data> <variable

    name="view" type="com.xrubio.databindingexample.ui.MainActivity"/> <variable name="data" type="com.xrubio.databindingexample.ui.ItemData"/> </data> <!-- Layout ... --> <Button android:text="Button" android:onClick="@{(btn) -> view.onClickButton(btn, data)}"/> fun onClickButton(btn: View, data: ItemData) { // ... }
  23. C

  24. C Creation of the layout Doesn't find new binding on

    first usage → Build→Clean Project
  25. C Error messages in Gradle Console lines are off-by-1 It

    is really line 47, column 30 e: java.lang.IllegalStateException: failed to analyze: java.lang.RuntimeException: Found data binding errors. ****/ data binding error ****msg:Cannot resolve type for IntConverter file:/Users/teknik/Documents/source/ _talks/android-data-binding-talk/databinding-example/app/src/main/res/layout/ activity_two_way_binding_conversion_converter.xml loc:46:29 - 46:62 ****\ data binding error **** 46:29
  26. R Google's Data Binding Library George Mount Medium articles Android

    Data Binding In Practice https://developer.android.com/topic/libraries/data- binding/index.html https://medium.com/@georgemount007 https://truveris.github.io/articles/android- advanced-data-binding/
  27. Q ?

  28. T ! Xavier Rubio Jansana This talk is available at:

     @teknik_tdr  https://xrubio.com  https://github.com/xrubioj/ https://xrubio.com/talks/talk-android-data-binding-from-null-to-data/