【问题标题】:Android Two-Way Data Binding with Double (Kotlin)Android 双向数据绑定与 Double (Kotlin)
【发布时间】:2020-11-26 12:30:10
【问题描述】:

我有一个ViewModel 类定义如下:

class StockLoadTaskModel : ViewModel() {
    ....
    ....
 
    var d: Double = 10.0
}

绑定到以下布局:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
    <data>
        <import type="android.view.View" />
        <import type="it.kfi.lorikeetmobile.extras.Converter" alias="Converter"/
        <variable
            name="viewModel"
            type="it.kfi.lorikeetmobile.stock.models.StockLoadTaskModel" />
        <variable
            name="view"
            type="it.kfi.lorikeetmobile.stock.ui.movements.StockLoadTaskFragment
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        ...
    
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="4dp"
            android:layout_marginEnd="8dp">
    
            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/et_code"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/hint_et_item_code"
                android:text="@={viewModel.itemCode}" />
        </com.google.android.material.textfield.TextInputLayout>
    
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="4dp"
            android:layout_marginEnd="8dp">
    
            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/et_quantity"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="numberDecimal"
                android:text="@={Converter.doubleToString(d)}"
                android:hint="@string/quantity" />
        </com.google.android.material.textfield.TextInputLayout>
    
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="4dp"
            android:layout_marginEnd="8dp">
    
            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/et_note"
                android:lines="3"
                android:scrollbars="vertical"
                android:overScrollMode="ifContentScrolls"
                android:gravity="top"
                android:inputType="textMultiLine"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/hint_et_note"
                android:text="@={viewModel.selectedItem.detail.note}"/>
        </com.google.android.material.textfield.TextInputLayout>
        
        ...
    </LinearLayout>

我还有以下Converter 对象:

object Converter {
    
    @JvmStatic
    @InverseMethod("stringToDouble")
    fun doubleToString(value: Double?): String? {
    
        if (value == null) {
            return null
        }
        return DecimalFormat(ClientConfiguration.currentConfig.decimalFormat).format(value)
    }
    
    @JvmStatic
    fun stringToDouble(value: String?): Double? {
    
        if (value == null) {
            return null
        }
        val v = DecimalFormat(ClientConfiguration.currentConfig.decimalFormat).parse(value)
        return v.toDouble()
    }
}

如果我设置:android:text="@={Converter.doubleToString(d)}"(双向数据绑定),在 ID 为 et_quantityEditText 中会出现以下错误:

...error: cannot find symbol

如果我将其更改为单向数据绑定,例如:android:text="@{Converter.doubleToString(d)}",它可以工作。绑定管理器似乎无法识别逆向方法。

有人可以帮我吗?谢谢。

【问题讨论】:

  • 使用MutableLiveData进行双向数据绑定,val d = MutableLiveData(10.0)
  • 最初不是“d”,而是一个 Room 实体,其类型为 Double 的数量字段存储在 MutableLiveData 中。它也不起作用。
  • 无论如何,“val d = MutableLiveData(10.0)”,不起作用....正如我所期望的那样
  • 奇怪,它对我有用。将Converter.doubleToString(d) 更改为Converter.doubleToString(viewModel.d) 你也忘了&gt;alias="Converter"/ 之后
  • 有,只是没有复制到剪贴板中。

标签: android kotlin data-binding android-databinding


【解决方案1】:

为什么会发生错误?

当您像 android:text="@={Converter.doubleToString(d)}" 这样定义双向数据绑定时,问题是:数据应该从哪里传递 EditText?它应该传递给Converter.doubleToString 还是Converter 的其他静态函数,可能是Converter.doubleToString(d) 的结果或d 变量?

你应该准确。

您期望它是d,编译器期望它是Converter.doubleToString(d) 的结果。实际上,两者都行不通。

现在,EditText 确实可以使用字符。它对 double、int、float、byte、short、boolean 或其他任何不是字符串的东西一无所知。

这意味着为了实现双向数据绑定您的源:

  • 必须返回值字符串类型;
  • 必须是可分配的。

如何解决这个问题?

Android 架构组件向我们介绍了ObservableField 类。有准备使用ObservableBooleanObservableCharObservableFloat 和其他一些。 如果您打开上一句中的链接,您应该会在左侧窗格中看到所有类 Observable...

没有ObservableStringObservableField 接受泛型类型。因此,您可以将作为数据绑定一部分的变量定义为ObservableField&lt;String&gt;("defaultValueHere")

所以你应该拥有的是:

class StockLoadTaskModel : ViewModel() {
    ....
    ....
    var d: Double = 10.0
    var dataBindingVariable = ObservableField<String>(d.toString())
}

dataBindingVariable 将始终返回您绑定到的EditText 的内容。您可以获得该值并安全地转换为 double。

class StockLoadTaskModel : ViewModel() {
    ....
    ....
    var d: Double = 10.0
    var dataBindingVariable = 
        object: ObservableField<String>(d.toString()) {
            override fun set(value: String?) {
                super.set(value)
                // a value has been set
                d = value.toDoubleOrNull() ?: d
            }
        }
}

布局声明将类似于输入字段:

        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="4dp"
            android:layout_marginEnd="8dp">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/et_quantity"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="numberDecimal"
                android:text="@={viewModel.dataBindingVariable}"
                android:hint="@string/quantity" />
        </com.google.android.material.textfield.TextInputLayout>

并且不需要object Converter

还有另一种双向数据绑定的方法,我在这里不谈,因为它已经得到解答。 Here it is.

【讨论】:

  • 嗨,珍妮亚。我给了你支票和赞成票,即使答案不是我所期望的。我的意思是,最后我可以创建一个带有 String 值的 MutableLiveData,然后在观察者中切换类型和分配。那将完成完全相同的工作。转换器更加有用和优雅(我可以在我的所有模型中重用它,而不添加额外的代码)......但就是这样。非常感谢您的宝贵帮助。
猜你喜欢
  • 2022-12-17
  • 2022-11-22
  • 1970-01-01
  • 2021-11-01
  • 2020-05-22
  • 2016-12-29
  • 1970-01-01
  • 1970-01-01
  • 2017-12-20
相关资源
最近更新 更多