在View上具有可观察的实例字段的双向数据绑定?

时间:2020-04-16 21:37:32

标签: android android-databinding android-binding-adapter

使用Android双向数据绑定时,我必须在BindingAdapter上使用静态View还是以某种方式简单地使用可观察的实例字段?在文档中,我始终只能在ViewModel上看到可观察的字段,而在View上却看不到。我尝试使用{p>在我的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侧上使用可观察字段?我想使用可观察字段而不是静态BindingAdapter的原因是我的View具有比我在BindingAdapter中无法处理的逻辑/状态更复杂的逻辑/状态(嗯,从静态{ {1}}我可以打电话给BindingAdapter,但在某种程度上对我来说是错的)

更新

我建立了一个最低限度的工作示例available on Github 默认情况下,它使用单向绑定,效果很好。更改

myViewInstance.myValue

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

将导致编译信息错误。使用activity_main.xml获得长输出,其中包括

./gradlew assembleDebug --stacktrace

谁能看看这个,让我知道我在做什么错?

1 个答案:

答案 0 :(得分:1)

使用Android双向数据绑定时,我是否必须在View上使用静态BindingAdapters,还是可以以某种方式简单地使用可观察的实例字段?

我认为您可以使用Observable实例字段来完成此操作。但是如果此逻辑也正在其他地方重用,我个人更喜欢使用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
}

最后,您的XML TextView应该看起来像这样:

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

让我知道这是否有效。



编辑

所以我们要寻找的基本上是BaseObservable类中的Bindable变量。让我们专注于三件事: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
... />

瞧!它应该工作。让我知道是否可以。