#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 и получить ответы на некоторые вопросы.