Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LiveData. Cannot assign to ‘value’: the setter is protected/*protected and package*/ for synthetic extension

I'm trying to implement a DB Observer with LiveData as described in the android documentation.

As long as I'm programming in Kotlin I'm adapting the functions (originally written in Java) to it.

When trying to save the data I find this problem.

Cannot assign to ‘value’: the setter is protected/*protected and package*/ for synthetic extension in ‘<library Grade: android.arch.livecycle:livedata-core-1.1.1>’

Did anyone have this problem already?

This is my code:

ViewModel:

class ProfileViewModel: ViewModel() {

    object FirstName: MutableLiveData<String>()

    fun getCurrentName(): LiveData<String> {
        return FirstName
    }
}

Fragment

class ProfileFragment{

    private lateinit var model: ProfileViewModel

    // this is called onViewCreated. inputFirstName is an Edittext.
    override fun setUp() {
        model = ViewModelProviders.of(this).get(ProfileViewModel::class.java)

        val nameObserver = Observer<String> { firstName ->
            inputFirstName.text = SpannableStringBuilder(firstName)
        }

        model.getCurrentName().observe(this, nameObserver)
    }

    fun saveProfileData() {
        val firstName = inputFirstName.text.toString()
        model.getCurrentName().value = firstName
    }
}
like image 442
kike Avatar asked Jun 19 '18 07:06

kike


People also ask

How do I declare LiveData?

Follow these steps to work with LiveData objects: Create an instance of LiveData to hold a certain type of data. This is usually done within your ViewModel class. Create an Observer object that defines the onChanged() method, which controls what happens when the LiveData object's held data changes.

What is difference between LiveData and MutableLiveData?

By using LiveData we can only observe the data and cannot set the data. MutableLiveData is mutable and is a subclass of LiveData. In MutableLiveData we can observe and set the values using postValue() and setValue() methods (the former being thread-safe) so that we can dispatch values to any live or active observers.


2 Answers

As @spkink suggested:

replace

fun getCurrentName(): LiveData<String>

with

fun getCurrentName(): MutableLiveData<String>

The error is caused because setValue(T value) is protected in LiveData (so you cannot call it) while it is public in MutableLiveData.

like image 57
RPG Avatar answered Oct 16 '22 02:10

RPG


model.getCurrentName().value = firstName

Please consider that handling the name value update inside the ViewModel might be a clearer solution, since you avoid having mutable public properties. Furthermore, here it could lead to even worse effects because you have two mutable public live data properties. For example:

ViewModel

// keep your MutableLiveData private, so it's easier to find where mutations might happen in your code
// I changed a little how the variable is declared, as the way below seems to more common nowadays
private var _firstName = MutableLiveData<String>()

// LiveData should remain public, being a read-only interface with other classes like your fragment
fun getCurrentName(): LiveData<String> {
    return _firstName
}

/*
An alternative 
val firstName = LiveData<String>
    get() = _firstName
*/

fun setFirstName(firstName: String){
    _firstName.value = firstName
}

Fragment

fun saveProfileData() {
    val firstName = inputFirstName.text.toString()
    // the value update will be handled inside the ViewModel, where the private mutable live data property is located
    model.setFirstName(firstName)
}
like image 1
alereca Avatar answered Oct 16 '22 03:10

alereca