Привязка данных и базовый сервер — Android MVVM

#kotlin #observer-pattern #android-databinding

#kotlin #наблюдатель-шаблон #android-привязка к данным

Вопрос:

У меня есть текстовое поле, которое привязано к данным модели представления, подобной приведенному здесь xml, и я хочу, чтобы пользовательский интерфейс обновлял поле txtProvider при нажатии на CardView. Как я должен уведомлять об изменении представления из моей viewmodel?

 <layout xmlns:bind="http://schemas.android.com/tools">
<data>
    <variable name="viewmodel"        
              type="io.leapingwolf.myapp.viewmodel.MyViewModel"/>
   <variable
    name="myModel"
    type="io.leapingwolf.myapp.models.MyModel"/>
</data>
    <android.support.v7.widget.CardView 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"   
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:id="@ id/cardView"
        app:cardCornerRadius="5dp"
        app:cardUseCompatPadding="true"
        android:onClick="@{viewmodel.onClickModel}">
        <TextView
            android:id="@ id/txtProvider"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:text="@{myModel.provider}"
            android:textColor="@android:color/black"
            android:textSize="15sp" />
    </android.support.v7.widget.CardView>
</layout>
  

В MyViewModel (который расширяет класс BaseObserver) у меня есть

 fun onClickModel() : View.OnClickListener {
        val viewOnClick = View.OnClickListener { v ->
                                myModel!!.provider = "name changed"
                                notifyPropertyChanged(BR.myModel)
                                Toast.makeText(context,"clicked:"   myModel!!.provider , Toast.LENGTH_SHORT).show()}
                                return viewOnClick
        }
  

Мой класс данных :

 data class MyModel(
        val type: String?,
        var  provider: String? 
) : AutoParcelable
  

Комментарии:

1. Как выглядит ваше текстовое поле?

2. txtProvider в файле макета является текстовым полем.

3. Итак, у вас нет переменной или свойства для текста в вашей viewmodel …?

4. Я подумал об этом и внес некоторые изменения в код. Я создал переменную для модели в файле макета и привязал свойство к текстовому полю. Затем я изменяю значение свойства в onClickModel и вызываю NotifyPropertyChanged. Тем не менее, изменения значения свойства не распространяются на пользовательский интерфейс. Пожалуйста, какие-либо указания

5. Пожалуйста, опубликуйте свой код. Мы не волшебники и можем только догадываться, что происходит не так.

Ответ №1:

Я заставил это работать в Kotlin, используя @Bindable в viewmodel, как показано ниже.Мне потребовалось некоторое время, чтобы понять, как использовать @Bindable в синтаксисе Kotlin. Свойство BR.provider не генерировалось, пока я не получил правильный синтаксис @Bindable.

 fun onClickModel(): View.OnClickListener {
    val viewOnClick = View.OnClickListener {
        route!!.provider = "name changed"
        notifyPropertyChanged(BR.provider)
    }
    return viewOnClick
}

val provider: String
    @Bindable
    get() {
        Log.d("Utils", "get property")
        return route!!.provider!!
    }
  

Ответ №2:

Я буду использовать синтаксис Java, потому что я не настолько свободно владею kotlin:

Вам нужно объявить свой MyModel или provider с DataBinding помощью, чтобы включить привязку. Используйте @Bindable средство получения данных on и вызывайте notifyPropertyChanged средство установки:

 @Bindable
public String getProvider() {
    return this.provider;
}

public void setProvider(String provider) {
    this.lastName = lastName;
    notifyPropertyChanged(BR.provider);
}
  

или сделайте свое MyModel расширение BaseObservable , или, поскольку у вас есть viewmodel, создайте ObservableField<String> или даже ObservableField<MyModel> :

 //in your viewmodel:
private ObservableField<MyModel> modelField = new ObservableField<MyModel>();
  

Установите значение в конструкторе вашей viewmodel, создайте средство получения и ссылайтесь на это в своем xml .

Комментарии:

1. Я заставил это работать в Kotlin, используя @Bindable в viewmodel, например

Ответ №3:

В вашем файле MyModel.kt

 class MyModel(
        @get:Bindable
        var provider: String = ""
) : BaseObservable() {
    fun updateText(str:String){
        provider = str
        notifyPropertyChanged(BR.counter)
    }
}
  

и затем в вашем layout.xml

 android:onClick="@{() -> myModel.updateText(`YOUR TEXT`)}"
  

Rebuild ваш проект, если вы не можете запустить BR.counter автозаполнение, работает

Ответ №4:

Возможно, это скорее проблема kotlin. Когда я инициализирую строку поставщика как ObservableField как

 var provider = ObservableField<String>()
init{
    provider = route.provider as ObservableField<String>
}
  

Я получаю ошибку во время выполнения
java.lang.Строка не может быть приведена к android.databinding.Наблюдаемое поле

Я попытаюсь опубликовать это на сайте обсуждения kotlin и получить ответы на некоторые вопросы.