代码之家  ›  专栏  ›  技术社区  ›  aksh1618

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

  •  0
  • aksh1618  · 技术社区  · 7 年前

    我正在尝试使用带有数据绑定的实时数据 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 只有当 目标 的值更改。

    有没有办法让它观察 目标.errorText ?

    2 回复  |  直到 7 年前
        1
  •  0
  •   janosch    7 年前

    有没有办法让它观察target.errorText?

    我不这么认为。问题是,数据绑定库正在解决 target 里面 target.errorText 首先看到它的类型 MutableLiveData<String> ,然后自动获取 目标 ,它的类型为String,然后尝试对该String对象调用getErrorText(),这将导致您看到的错误。

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

    class <T> ValidatableValue {
    
        val liveData = MutableLiveData<T>() // The actual value.
    
        // Other helper livedatas and functions.
        val isValid = MutableLiveData<Boolean>()
        val errorMessage = MutableLiveData<String>()
    
        fun validate() { ... }
    }
    

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

        2
  •  0
  •   Sergei Bubenshchikov    7 年前

    它是 坏模式 将视图模型传递为 字段集 而不是一个复合对象。 如果需要将至少两个变量传递给数据绑定,则需要使用该字段创建视图模型——这有助于使更改更加灵活。

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

    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 ,但它允许您的数据在开箱即用的配置更改中生存