Двусторонняя привязка данных с LiveData не работает должным образом - PullRequest
0 голосов
/ 14 апреля 2020

Мне нужна небольшая помощь в соответствии с последним этапом двухсторонней привязки данных на счетчике. Сначала моя ViewModel:

class MainViewModel : ViewModel() {

  // getLanguages() returns the LiveData
  private val _availableLanguages: LiveData<List<LanguageItem>> = MutableLiveData(languageList)
  val languages: LiveData<List<LanguageItem>> = _availableLanguages

  val selectedLanguage = MutableLiveData<LanguageItem>()

  // This is just for debugging - it should show the language code and name of the selected LanguageItem
  val showResultInView = MutableLiveData("Code: ${selectedLanguage.value?.languageCode} Name: ${selectedLanguage.value?.languageName}")

XML Файл:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
    <variable name="settingsViewModel" type="com.example.spinnertest.ui.main.MainViewModel" />
</data>
<LinearLayout
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <Spinner
        android:id="@+id/fragment_settings_language_spinner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/margin_left"
        android:layout_marginEnd="@dimen/margin_right"
        app:languages="@{settingsViewModel.languages}"
        app:selectedLanguage="@={settingsViewModel.selectedLanguage}" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@={settingsViewModel.showResultInView}" />
</LinearLayout>

Адаптер привязки данных:

/**
 * Fill the spinner with all available languages.
 * Set the Spinner selection to selectedLanguage.
 * If the selection changes, call the InverseBindingAdapter
 */
@BindingAdapter(value = ["languages", "selectedLanguage", "selectedLanguageAttrChanged"], requireAll = false)
fun setLanguages(spinner: Spinner, languages: List<LanguageItem>?, selectedLanguage: LanguageItem?, listener: InverseBindingListener?) {
   if(languages == null) return

   // assign the adapter to the spinner if not already done
   if (spinner.adapter == null)
       spinner.adapter = LanguageAdapter(spinner.context, android.R.layout.simple_spinner_dropdown_item, languages)

   if (selectedLanguage == null)
       setCurrentSelection(spinner, spinner.selectedItem as LanguageItem)
   else
       setCurrentSelection(spinner, selectedLanguage)

   // assign listener to the spinner if not already done
   listener?.apply { setSpinnerListener(spinner, this) }
}

@InverseBindingAdapter(attribute = "selectedLanguage")
fun getLanguages(spinner: Spinner): LanguageItem {
    return spinner.selectedItem as LanguageItem
}

// HELPER //
private fun setCurrentSelection(spinner: Spinner, selectedItem: LanguageItem?): Boolean {
   if (selectedItem == null) return false
   for (index in 0 until spinner.adapter.count) {
       val currentItem = spinner.getItemAtPosition(index) as LanguageItem
       if (currentItem == selectedItem)  {
           spinner.tag = spinner.selectedItemPosition // Set a tag witch current position to stop infinetly loop in onItemSelectListener easy
           spinner.setSelection(index)
           return true
       }
   }
   return false
}

private fun setSpinnerListener(spinner: Spinner, listener: InverseBindingListener) {
   if (spinner.onItemSelectedListener == null) {
       spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
        override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
            val tmp = parent?.tag ?: 0
            if (tmp != position)
                return listener.onChange()
            else
                return
        }
        override fun onNothingSelected(parent: AdapterView<*>?) {
            return listener.onChange()
        }
    }
   }
}

Так что я ожидаю, что selectedLanguage будет обновляться, когда элемент был изменен с счетчика, и поэтому также будет обновлен showResultInView. Но когда я отлаживаю материал, кажется, что selectedLanguage не обновляется из кода адаптера привязки данных.

Что такое недостающая часть. Я не мог видеть это?

С уважением, Фрэнк

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...