Android Double双向数据绑定(Kotlin)

时间:2020-08-06 09:05:36

标签: android kotlin data-binding android-databinding

我有一个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为EditText的{​​{1}}中,出现以下错误:

et_quantity

如果我将其更改为单向数据绑定,例如:...error: cannot find symbol ,则它可以工作。看来绑定管理器无法识别逆方法。

有人可以帮助我吗?谢谢。

1 个答案:

答案 0 :(得分:2)

为什么会发生错误?

当您像这样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...

没有ObservableString,但是ObservableField接受通用类型。因此,您可以将作为数据绑定一部分的变量定义为ObservableField<String>("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