web-dev-qa-db-fra.com

Liaison de données en direct et de données bidirectionnelles: le setter personnalisé n'est pas appelé

J'utilise une liaison de données bidirectionnelle pour mettre à jour un objet String LiveData de mon ViewModel avec une chaîne définie dans EditText:

<Android.support.design.widget.TextInputEditText
  Android:id="@+id/writeReviewTitle"
  Android:layout_width="match_parent"
  Android:layout_height="wrap_content"
  Android:text="@={viewModel.liveReviewTitle}"
/>

Donc, d'après ma compréhension, l'attribut ViewModel verrait son attribut liveReviewTitle mis à jour à chaque fois que le texte change dans EditText. Je suppose que cela se produit par l'utilisation d'un TextWatcher ou d'une sorte de mécanisme d'écoute dont la bibliothèque s'occupe pour moi. Je pensais également que lorsque le texte devait être mis à jour, son setter serait appelé. Ce qui ne semble pas être le cas! Lorsque le texte change, j'ai besoin de faire plus de choses dans mon ViewModel, donc j'ai implémenté un setter personnalisé pour liveReviewTitle, mais c'est pas appelé (I essayé le débogage). Voici à quoi cela ressemble dans la classe ViewModel:

var liveReviewTitle: MutableLiveData<String> = MutableLiveData()
        set(value) {
            field = value
            customLogicHere()
        }

J'ai essayé de déboguer ce setter mais il ne semble jamais être appelé! Que se passe-t-il ici? Sent un peu déroutant. Le texte est en cours de mise à jour et il est enregistré dans le ViewModel, c'est juste le setter qui n'est pas appelé.

Bien sûr, il n'est jamais appelé, vous ne définissez pas un nouveau MutableLiveData, vous définissez une nouvelle valeur String à l'intérieur du MutableLiveData (éventuellement avec setValue).

Cependant, vous devriez pouvoir intercepter la valeur définie et exécuter une logique personnalisée après avoir défini la valeur si vous exposez directement un MediatorLiveData au lieu du MutableLiveData.

EDIT: les éléments suivants devraient fonctionner comme prévu:

val liveReviewTitle: MutableLiveData<String> = MutableLiveData()
private val mediator = MediatorLiveData<String>().apply {
    addSource(liveReviewTitle) { value ->
        setValue(value)
        customLogicHere()
    }
}.also { it.observeForever { /* empty */ } }
6
EpicPandaForce

La solution @EpicPandaForce est appropriée mais dans EditText la liaison bidirectionnelle peut être obtenue de manière beaucoup plus simple. Ajoutez l'attribut afterTextChanged à votre widget comme ci-dessous:

Android:afterTextChanged="@{viewModel::doLogic}"

Ensuite, dans votre classe ViewModel, écrivez simplement la méthode:

fun doLogic(s: Editable) { //update Livedata or do other logic }

[~ # ~] modifier [~ # ~]

J'ai raté une documentation importante note . Beaucoup plus facile (et beaucoup plus propre) sera:

Android:text="@={viewModel.someLivedata}

puis dans notre classe LifecycleOwner, nous pouvons mettre à jour la valeur de liveData quand nous en avons besoin, et bien sûr nous pouvons réagir aux changements de l'observateur enregistré.

3
Karol Kulbaka

@EpicPandaForce a raison pour votre setter, c'est pour le MutableLiveData lui-même et non pour la valeur qu'il contient. Donc, votre LiveData doit être un val, pas besoin que ce soit un var, et le framework doit faire la bonne chose tant que vous définissez un LifecycleOwner sur la reliure. Vous pouvez ajouter un autre Observer à votre LiveData à la place d'un setter personnalisé pour ajouter votre logique personnalisée.

2
Mateo