【问题标题】:Unable to access property of custom LiveData using Data binding无法使用数据绑定访问自定义 LiveData 的属性
【发布时间】:2019-02-01 11:59:36
【问题描述】:

我正在尝试使用像这样的类将实时数据与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的变化,仅当target的值发生变化时更新errorText

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

【问题讨论】:

    标签: android kotlin android-databinding android-livedata


    【解决方案1】:

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

    我不这么认为。问题是,数据绑定库首先在target.errorText 中解析target,并发现它是MutableLiveData&lt;String&gt; 类型,然后它会自动获取target 的值,它是String 类型的,然后尝试调用getErrorText() 在那个 String 对象上,这会导致你看到的错误。

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

    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】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多