简体   繁体   中英

Why does my data-binding with EditText not work?

I have this class which I use for Room:

data class Piece(
    @ColumnInfo(name = "title")
    var title: String
)

Then I have a form class, which simply holds string values which I want to be shown in EditText .

class CreateEditPieceForm {
    var title: String = ""
}

My ViewModel holds instances of these classes:

class EditPieceViewModel(...) : AndroidViewModel(application) {
    val piece : LiveData<Piece?> = database.getMyPiece() // valid Piece with title set
    val form = CreateEditPieceForm()
}

In my fragment I observe the piece:

viewModel.piece.observe(this, Observer {piece ->
   piece?.let {
       viewModel.updateInputValues(piece)
    }
})

updateInputValues function in the ViewModel simply sets values in the form:

   fun updateInputValues(piece: Piece) {
        Log.d("mylog", "value: " + piece.title) // logs correct value
        form.title = piece.title // setting this does not change EditText
   }

And finally, in my layout, I try to use data binding to show the text from form.title in EditText:

<data>

  <variable
            name="viewModel"
            type="com.example.tutorial.createedit.CreateEditPieceViewModel" />

</data>

<!-- ... -->

  <EditText
            android:id="@+id/input_title"
            <!-- ... -->
            android:inputType="text"

            android:text="@={viewModel.form.title}" />

When I open the Screen with this fragment, EditText is empty. I know that the query for piece title is correct, because I log it before I set EditText's text attribute.

When I type something in the empty field, value of viewModel.form.title is being set with that value.

Why does it not set right at the beginning?

Databinding is not to be confused with View binding .

Like in the guide, make EditPieceViewModel implement Observable and make form.title @Bindable.

Now it works. I still do not fully understand the Databinding library, so any advice to improve the code is welcomed!

I changed my ViewModel to implement Observable and added some methods to it:

// Make sure to import the correct Observable interface
import androidx.databinding.Observable
// ...

class EditPieceViewModel(...) : AndroidViewModel(application), Observable {

   // ...

   // New getter and setter methods for my title field:

    @Bindable
    fun getTitle() : String {
        return form.title
    }

    fun setTitle(value: String) {
        if(form.title != value) {
            form.title = value
            notifyPropertyChanged(BR.title) // This line is important for EditText' value to update
        }
    }


   // New methods added for Observable:

    override fun addOnPropertyChangedCallback(
        callback: Observable.OnPropertyChangedCallback) {
        callbacks.add(callback)
    }

    override fun removeOnPropertyChangedCallback(
        callback: Observable.OnPropertyChangedCallback) {
        callbacks.remove(callback)
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes should be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    fun notifyPropertyChanged(fieldId: Int) {
        callbacks.notifyCallbacks(this, fieldId, null)
    }

}

In layout xml I changed title to observe viewModel.title instead of viewModel.form.title:

        <EditText
            // ...
            android:text="@={viewModel.title}" />

Finally in updateInputValues I call my custom setter:

fun updateInputValues(piece: Piece) {
        setTitle(piece.title)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM