使用数据绑定无法访问自定义LiveData的属性

时间:2019-02-01 11:59:37

标签: android kotlin android-databinding android-livedata

我正在尝试使用像这样的类对TextInputLayout使用实时数据和数据绑定:

class MutableLiveDataWithErrorText<T> : MutableLiveData<T>() {
    val errorText = MutableLiveData<String>().apply { value = "" }
}

现在,当尝试将其用于xml中的错误文本时,

<layout>
    <data>
        <!-- ... -->
        <variable
            name="target"
            type="com.my.app.MutableLiveDataWithErrorText&lt;String&gt;" />

    </data>

    <com.google.android.material.textfield.TextInputLayout
        app:errorEnabled="true"
        app:errorText="@{target.errorText}">

        <!-- ... -->

    </com.google.android.material.textfield.TextInputLayout>
</layout>

我收到此错误:

Cannot find getter 'getErrorText' for type String.

我尝试创建BindingAdapter来解决此问题:

@BindingAdapter("errorTextLive")
fun setErrorTextLive(
    view: TextInputLayout,
    liveDataWithErrorText: MutableLiveDataWithErrorText<String>
) {
    if (liveDataWithErrorText.errorText.value.isNullOrEmpty().not()) {
        view.error = liveDataWithErrorText.errorText.value
    }
}

xml分配更改为:

app:errorTextLive="@{target}"

这使编译成功,但是不再观察到target.errorText的更改,而是观察target的更改,仅在errorText的值更改时更新target

有没有办法让它遵守target.errorText

2 个答案:

答案 0 :(得分:0)

  

有没有办法让它遵守target.errorText?

我不这么认为。问题在于,数据绑定库首先在var内解析target并发现其类型为target.errorText,然后它会自动获取MutableLiveData<String>的值,即类型为String的对象,然后尝试在该String对象上调用getErrorText(),这会导致您看到错误。

我有一个类似的用例,我求助于创建以下类:

target

然后我可以在数据绑定布局中使用所有这些LiveData对象。

答案 1 :(得分:0)

将视图模型作为一组字段而不是一个复合对象传递是错误模式。 如果需要将至少两个变量传递给数据绑定,则需要使用此字段创建视图模型-这样可以帮助您更灵活地进行更改。

例如,您可以像这样定义视图模型:

class SimpleViewModel : ViewModel() {

    /**
     * Expose MutableLiveData to enable two way data binding
     */
    val textData = MutableLiveData<String>().apply { value = "" }
    /**
     * Expose LiveData for read only fields
     */
    val errorText = Transformations.map(textData, ::validateInput)

    /**
     * Validate input on the fly
     */
    private fun validateInput(input: String): String? = when {
        input.isBlank() -> "Input is blank!"
        else -> null
    }
}

在布局方面,它非常接近您的变体形式:

<layout>
    <data>
        <variable
            name="vm"
            type="com.example.SimpleViewModel" />

    </data>

    <android.support.design.widget.TextInputLayout
        app:errorEnabled="true"
        app:errorText="@{vm.errorText}">

        <android.support.design.widget.TextInputEditText
            android:text="@={vm.textData}"/>

    </android.support.design.widget.TextInputLayout>
</layout>

注意:不必SimpleViewModel扩展ViewModel,但它允许您的数据在配置更改后立即使用