Двусторонняя привязка данных с наблюдаемыми полями экземпляра в представлении? - PullRequest
0 голосов
/ 17 апреля 2020

При использовании Android двусторонней привязки данных, нужно ли использовать stati c BindingAdapter s на View или можно как-то просто использовать наблюдаемые поля экземпляра? В документации я всегда вижу наблюдаемые поля только на ViewModel s, а не на View. Я попытался реализовать наблюдаемые поля на моем View с помощью

var myValue: String = ""
@Bindable get(): String {
    return field
}
set(value: String) {
    field=value
    setText(value)
    notifyPropertyChanged(BR.myValue) // my View implements the Observable interface
}

, но когда я скомпилировал это (с помощью ./gradlew assembleDebug --stacktrace, чтобы получить подробности), это не удалось с

ERROR: Cannot find a getter for <com.example.test.MyAutoCompleteTextView app:myValue> 
that accepts parameter type 'java.lang.String'

If a binding adapter provides the getter, check that the adapter is annotated correctly
and that the parameter type matches. 

Итак, Разве нельзя использовать наблюдаемые поля на стороне View двусторонней привязки данных, как это возможно на ViewModel? Причина, по которой я хочу использовать наблюдаемые поля вместо stati c BindingAdapter s, заключается в том, что мой View имеет более сложную логику / состояние, чем я могу обработать в BindingAdapter (ну, из состояния c BindingAdapter Я мог бы просто позвонить на myViewInstance.myValue, но почему-то мне это кажется неправильным)

Обновление

Я создал минимальный (не) рабочий пример, доступно на Github По умолчанию используется односторонняя привязка, которая отлично работает. Изменение

app:myValue="@{viewModel.realValue}"

на

app:myValue="@={viewModel.realValue}"

в activity_main.xml приведет к не очень информативным ошибкам компиляции. Используйте ./gradlew assembleDebug --stacktrace, чтобы получить длинный вывод, который включает

ERROR: Cannot find a getter for 
<com.example.test.MyAutoCompleteTextView app:myValue> 
that accepts parameter type 'java.lang.String'

Может кто-нибудь взглянуть на это и сообщить мне, что я делаю неправильно?

1 Ответ

1 голос
/ 21 апреля 2020

При использовании двусторонней привязки данных Android нужно ли мне использовать stati c BindingAdapters в представлении или можно каким-то образом просто использовать наблюдаемые поля экземпляров?

Я думаю, что вы можете сделать это с помощью наблюдаемых полей экземпляра. Однако , если этот лог c также используется где-то еще, я лично предпочел бы использовать BindingAdapters.

В вашем классе Observable измените свой код следующим образом:

@get:Bindable
var myValue: String = ""
    set(value) {
        field = value 
        notifyPropertyChanged(BR.myValue) // my View implements the Observable interface
    }

Я проверил ваш репозиторий и понял, что вы используете MutableLiveData, так что вам не нужен вышеуказанный код в этом случае. Я также не смог найти там BindingAdapter. Убедитесь, что ваш код BindingAdapter выглядит примерно так:

@BindingAdapter("myValue")
@JvmStatic
fun TextView.setMyValue(realValue: String) {
    val finalValue : String = realValue.dataManipulation() // Do your data manipulation here
    setText(finalValue) // Make sure it's a string
}

И, наконец, ваш TextView в XML должен выглядеть следующим образом:

<com.example.test.MyAutoCompleteTextView
    ...
    app:myValue="@{viewModel.realValue}"
    ... />

Дайте мне знать, если это сработало.



EDIT

Итак, мы ищем в основном переменные Bindable в классе BaseObservable. Давайте сосредоточимся на трех вещах: ваша XML, ваша деятельность / фрагмент и ваш класс BindingModel.

Ваш класс BindingModel в основном расширяет ваш класс BaseObservable.

class BindingModel: BaseObservable(){
    @get:Bindable
    var myValue: String = ""
        set(value) {
            var finalValue = manipulateData(value) //Write your logic here
            field = finalValue
            notifyPropertyChanged(BR.myValue) // my View implements the Observable interface
    }
...
}

В вашей деятельности / фрагменте, создать переменную типа BindingModel. Наблюдайте за вашими LiveData и обновляйте переменную.

class MainActivity : AppCompatActivity() {
...
val model = BindingModel()
...
override fun onCreate(savedInstanceState: Bundle?) {
    ...
    binding.lifecycleOwner = this // Specify the current activity as the lifecycle owner.
    binding.model = model
    viewModel.realValue.observe(this, Observer {
        model.myValue = it
    })
} // End of onCreate()
...
} // End of Activity code

Переходя к вашему XML, вам нужно объявить model переменную привязки данных там.

...
<data>
...
<variable
    name="model" //Make sure the name is same
    type="com.example.test.<path-to-your-file>.BindingModel" />
</data>
...
<com.example.test.MyAutoCompleteTextView
...
android:text="@{model.realValue}" //Don't forget this
... />

И вуаля! Он должен работать. Дайте мне знать, если это не так.

...