Мне нужна небольшая помощь в соответствии с последним этапом двухсторонней привязки данных на счетчике. Сначала моя 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 не обновляется из кода адаптера привязки данных.
Что такое недостающая часть. Я не мог видеть это?
С уважением, Фрэнк