0

I have ViewModel:

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

    val user: LiveData<String> = _user

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

I connected it with fragment layout using:

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

And in fragment class in onCreateView method:

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

I can change the EditText value from the fragment or ViewModel class, but when I try to get the value inside the onBtnClick method of the ViewModel in the Logcat I am getting the message: I/MyViewModel: user: What am I missing here so that two-way data binding works from the other direction too? I nutshell, data goes from ViewModel/ Fragment to EditText on the interface, but it doesn't flow from EditText on the interface to ViewModel fields/ methods. Thanks in advance.

------- EDITED ----- I managed to populate everything, but know I am getting this error:

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

I suppose that is because viewmodel.user is of type LiveData and not of a String. I have written binding adapter:

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

But I am still getting the above message.

M.Vas
  • 1
  • 1
  • 3

2 Answers2

2

First, you need to make _user public. Then you need to use "@={viewmodel._user}", so that you can get the value of _user. Databinding API can't figure out and generate code if you don't make your databinding variable public. For simple fields such as Strings, this approach will suffice, but you may have to implement BindingAdapters for more complex situations. See this article for examples.

Alvin Dizon
  • 1,855
  • 14
  • 34
  • I have seen that, and put '@=' but it then produces error: symbol: class FragmentMyFragmentBindingImpl location: package com.pkg.pkg.databinding – M.Vas Sep 29 '19 at 23:07
  • @M.Vas, edited my answer, since you have named the variable ```_user``` in your viewmodel, you have to use the exact name with the underscore in the XML as well – Alvin Dizon Sep 29 '19 at 23:26
  • Thanks, I have edited my question since it would be too long to answer in the comment. – M.Vas Sep 29 '19 at 23:59
  • thanks. just needed to put an = and my life was save. thanks a lot. looking for it since so long I almost gave up. – Fazal Aug 15 '20 at 22:19
0

The answer to this question in order to work you should add this to build.gradle:

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

And kotlin version should be downgraded:

ext.kotlin_version = '1.3.41'

Cheers!

M.Vas
  • 1
  • 1
  • 3