Android Simple Two Way Data Binging With Spinner Without BindingAdapter (Kotlin)

March 11, 2018

I have a List<Category> which loaded into Spinner using ArrayAdapter. I wanted to use Data Binding to get and set the value of the spinner.

If you are loading Enum into Spinner, you should read this guide and use @InverseMethod.

A more complete and complex solution would usually involve BindingAdapter or InverseBindingAdapter, but I wanted something simpler.

The simplest solution is to bind selectedItemPosition position.

class CategoryViewModel() : ViewModel() {
  val categoryIdItemPosition = MutableLiveData<Int>()
}
<Spinner
    android:id="@+id/categorySpinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:selectedItemPosition="@={viewModel.categoryIdItemPosition}"
/>
val position = viewModel.categoryIdItemPosition.value
viewModel.categoryIdItemPosition.value = position + 1

Though I can set/get position, but I can’t actually get the actual selected item’s ID or set selected item by ID. I can write a convenient property to do this.

class CategoryViewModel() : ViewModel() {

  val categoryIdItemPosition = MutableLiveData<Int>()
  var categoryIdValue
      get() =
          categoryIdItemPosition.value?.let {
               categoryList?.get(it)?.id
          }
      set(value) {
          val position = categoryList?.indexOfFirst {
              it.id == value
          } ?: -1
          if (position != -1) {
              categoryIdItemPosition.value = position
          }
      }  

  var categoryList List<Cateogory>? = null
}

NOTE: when you assign List<Category> to spinner’s adapter, update viewModel.categoryList as well.

I can also write a convenient property to get selected item.

class CategoryViewModel() : ViewModel() {

  val categoryIdItemPosition = MutableLiveData<Int>()
  var categoryIdValue
      get() =
          categoryIdItemPosition.value?.let {
               categoryList?.get(it)?.id
          }
      set(value) {
          val position = categoryList?.indexOfFirst {
              it.id == value
          } ?: -1
          if (position != -1) {
              categoryIdItemPosition.value = position + 1
          }
      }  
  val categoryIdItem
    get() =
        categoryIdItemPosition.value?.let {
             categoryList?.get(it)
        }

  var categoryList List<Cateogory>? = null
}

NOTE: if you are not using ViewModel, you can access List<Cateogory> using Spinner and Adapter methods.

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.