Android Two Way Databinding работает только в одну сторону

У меня есть ViewModel:

class MyViewModel : ViewModel(){
    private val _user = MutableLiveData("")

    val user: LiveData<String> = _user

    fun onBtnClick(){
        Log.i("MyViewModel", "user: ${_user.value}")
    }
}

Я связал его с макетом фрагмента, используя:

<data>
    <variable
        name="viewmodel"
        type="com.pkg.pkg.pkg.fragments.concretePkg.MyViewModel" />
</data>
<EditText
    ...
    android:text="@={viewmodel.user}"
    android:hint="User" />

И в классе фрагмента в методе onCreateView:

binding = DataBindingUtil.inflate(inflater, R.layout.fragment_my_fragment, container, false)
binding.lifecycleOwner = this
// bind viewModel
viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
binding.viewmodel = viewModel

// Inflate the layout for this fragment
return binding.root

Я могу изменить значение EditText из фрагмента или класса ViewModel, но когда я пытаюсь получить значение внутри метода onBtnClick ViewModel в Logcat, я получаю сообщение: I/MyViewModel: user: Что мне здесь не хватает, чтобы двусторонняя привязка данных с другой стороны тоже работает? В двух словах, данные передаются из ViewModel/Fragment в EditText в интерфейсе, но не передаются из EditText в интерфейсе в поля/методы ViewModel. Заранее спасибо.

------- ОТРЕДАКТИРОВАНО ----- Мне удалось заполнить все, но я знаю, что получаю эту ошибку:

Details: There is no inverse for method getValue, you must add an @InverseMethod annotation to the method to indicate which method should be used when using it in two-way binding expressions

Я полагаю, это потому, что viewmodel.user имеет тип LiveData, а не String. Я написал адаптер привязки:

@BindingAdapter("android:text")
    fun setLiveDataText(editText: EditText, liveData: LiveData<String>) {
            if(liveData == null){
                editText.setText("")
            } else {
                editText.setText(liveData.value)
            }
        }

Но я все еще получаю вышеуказанное сообщение.


person M.Vas    schedule 29.09.2019    source источник


Ответы (2)


Во-первых, вам нужно сделать _user общедоступным. Затем вам нужно использовать "@={viewmodel._user}", чтобы вы могли получить значение _user. API привязки данных не сможет определить и сгенерировать код, если вы не сделаете свою переменную привязки данных общедоступной. Для простых полей, таких как строки, этого подхода будет достаточно, но вам, возможно, придется реализовать BindingAdapters для более сложных ситуаций. Примеры см. в этой статье.

person akubi    schedule 29.09.2019
comment
Я видел это и поставил '@=', но затем выдает ошибку: символ: класс FragmentMyFragmentBindingImpl расположение: пакет com.pkg.pkg.databinding - person M.Vas; 30.09.2019
comment
@M.Vas, отредактировал мой ответ, поскольку вы назвали переменную _user в своей модели представления, вы также должны использовать точное имя с подчеркиванием в XML. - person akubi; 30.09.2019
comment
Спасибо, я отредактировал свой вопрос, так как ответ в комментарии был бы слишком длинным. - person M.Vas; 30.09.2019
comment
Спасибо. просто нужно было поставить = и моя жизнь была спасена. большое спасибо. искал его так долго, что чуть не сдался. - person Fazal; 16.08.2020

Ответ на этот вопрос для работы вы должны добавить это в build.gradle:

implementation "android.arch.lifecycle:extensions:1.1.1"

И версия kotlin должна быть понижена:

ext.kotlin_version = '1.3.41'

Ваше здоровье!

person M.Vas    schedule 30.09.2019