Android 带参数的方法的双向数据绑定
Android two-way databinding for methods with parameters
模型的 Setter 和 getter 方法有一个参数,像这样:
public int getPrice(Object key) {
}
public void setPrice(Object key, int price) {
}
XML 看起来像这样:
<EditText
android:id="@+id/edtPrice"
style="@style/CreateShipperItemValueEditTextView"
android:layout_centerVertical="true"
android:hint="@string/hint_price"
android:inputType="number"
android:maxLines="1"
android:text="@={shipper.getPrice(priceKey)}"/>
android:text="@={shipper.getPrice(priceKey)}"
构建期间的编译器错误表明我们应该使用@InverseMethod 注释。
我尝试这样的事情:
@InverseMethod(value = "getPrice")
@Override
public void setPrice(Object key, int price) {
super.setPrice(key, price);
}
但是在这种情况下我有下一个错误。
error: @InverseMethods must have a non-void return type
所以我很乐意在这里对整个流程进行很好的解释。谢谢
在这种情况下,与其编写自己的绑定方法,不如考虑使用 ObservableMap
。
public final ObservableMap<Object, Integer> price = new ObservableArrayMap<>();
<EditText
android:id="@+id/edtPrice"
style="@style/CreateShipperItemValueEditTextView"
android:layout_centerVertical="true"
android:hint="@string/hint_price"
android:inputType="number"
android:maxLines="1"
android:text="@={shipper.price[priceKey]}"/>
但问题在于将文本值 (CharSequence
) 转换为映射值 (int
)。为此,您需要 @InverseMethod
。在您的情况下,这种方法是不够的。所以你需要提供一个 @InverseBindingAdapter
来代替。
@InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
public static Integer convertTextToInteger(EditText view) {
String text = view.getText().toString();
return text.isEmpty() ? null : Integer.parseInt(text);
}
此外,您还必须提供 @BindingConversion
或 @BindingAdapter
以将整数映射到 CharSequence
以首先设置文本。
@BindingConversion
public static CharSequence convertMyClass(Integer i) {
return i == null ? null : i.toString();
}
很高兴看到您正在使用 Android Studio 3.0 中提供的新 InverseMethod。
您正在使用一种方法进行双向数据绑定,并且表达式必须了解用户修改文本时如何设置值。该用途旨在用于转换方法,因此我不知道这是否适用于您的情况。
本质上,数据绑定在将文本设置到视图时使用如下代码:
EditText edit = binding.edtPrice;
edit.setText(shipper.getPrice(priceKey));
当文本发生变化时,您要求它这样做:
EditText edit = binding.edtPrice;
priceKey = shipper.setPrice(priceKey, edit.getText());
这显然是行不通的,它会给你一个错误。
确实有两点不对。第一个是 getPrice()
return 是 int
而不是 CharSequence
或 String
。第二个是 setPrice()
并没有真正进行转换——它需要不同数量的参数并且 return 是 void
.
在你的例子中,你并没有试图将 priceKey 转换成一个整数;您正在尝试访问某种地图中的值。有几种方法可以处理这个问题。我认为最简单的方法是直接在模型中使用地图。在这里,我假设您有一个 final 字段,但您可以使用 getter 和 setter 将其 return 作为 属性:
public class ShipperModel {
public final ObservableArrayMap<Object, Integer> price = new ObservableArrayMap<>();
//...
}
然后在你的表达中:
<EditText android:text="@={`` + shipper.price[priceKey]}" .../>
如果你想要自定义转换,你可以这样做:
@InverseMethod("convertToPrice")
public String convertFromPrice(Object key, int price) {
//...
}
public int convertToPrice(Object key, String text) {
//...
}
然后您将在表达式中传递价格对象:
<EditText android:text="@={shipper.convertFromPrice(priceKey, shipper.price)}" .../>
我会简化转换方法,使它们可在我的整个应用程序中重复使用,只需将整数转换为字符串并返回:
public class Converters {
@InverseMethod("fromPrice")
public static final int toPrice(String text) {
//...
}
public static final String fromPrice(int price) {
//...
}
}
然后表达式将是:
<EditText android:text="@={Converters.fromPrice(shipper.price[priceKey])}" .../>
Setter 和 getter 方法有一个参数,像这样:
public int getPrice(Object key) {
}
public void setPrice(Object key, int price) {
}
XML 看起来像这样:
<EditText
android:id="@+id/edtPrice"
style="@style/CreateShipperItemValueEditTextView"
android:layout_centerVertical="true"
android:hint="@string/hint_price"
android:inputType="number"
android:maxLines="1"
android:text="@={shipper.getPrice(priceKey)}"/>
android:text="@={shipper.getPrice(priceKey)}"
构建期间的编译器错误表明我们应该使用@InverseMethod 注释。 我尝试这样的事情:
@InverseMethod(value = "getPrice")
@Override
public void setPrice(Object key, int price) {
super.setPrice(key, price);
}
但是在这种情况下我有下一个错误。
error: @InverseMethods must have a non-void return type
所以我很乐意在这里对整个流程进行很好的解释。谢谢
在这种情况下,与其编写自己的绑定方法,不如考虑使用 ObservableMap
。
public final ObservableMap<Object, Integer> price = new ObservableArrayMap<>();
<EditText
android:id="@+id/edtPrice"
style="@style/CreateShipperItemValueEditTextView"
android:layout_centerVertical="true"
android:hint="@string/hint_price"
android:inputType="number"
android:maxLines="1"
android:text="@={shipper.price[priceKey]}"/>
但问题在于将文本值 (CharSequence
) 转换为映射值 (int
)。为此,您需要 @InverseMethod
。在您的情况下,这种方法是不够的。所以你需要提供一个 @InverseBindingAdapter
来代替。
@InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
public static Integer convertTextToInteger(EditText view) {
String text = view.getText().toString();
return text.isEmpty() ? null : Integer.parseInt(text);
}
此外,您还必须提供 @BindingConversion
或 @BindingAdapter
以将整数映射到 CharSequence
以首先设置文本。
@BindingConversion
public static CharSequence convertMyClass(Integer i) {
return i == null ? null : i.toString();
}
很高兴看到您正在使用 Android Studio 3.0 中提供的新 InverseMethod。
您正在使用一种方法进行双向数据绑定,并且表达式必须了解用户修改文本时如何设置值。该用途旨在用于转换方法,因此我不知道这是否适用于您的情况。
本质上,数据绑定在将文本设置到视图时使用如下代码:
EditText edit = binding.edtPrice;
edit.setText(shipper.getPrice(priceKey));
当文本发生变化时,您要求它这样做:
EditText edit = binding.edtPrice;
priceKey = shipper.setPrice(priceKey, edit.getText());
这显然是行不通的,它会给你一个错误。
确实有两点不对。第一个是 getPrice()
return 是 int
而不是 CharSequence
或 String
。第二个是 setPrice()
并没有真正进行转换——它需要不同数量的参数并且 return 是 void
.
在你的例子中,你并没有试图将 priceKey 转换成一个整数;您正在尝试访问某种地图中的值。有几种方法可以处理这个问题。我认为最简单的方法是直接在模型中使用地图。在这里,我假设您有一个 final 字段,但您可以使用 getter 和 setter 将其 return 作为 属性:
public class ShipperModel {
public final ObservableArrayMap<Object, Integer> price = new ObservableArrayMap<>();
//...
}
然后在你的表达中:
<EditText android:text="@={`` + shipper.price[priceKey]}" .../>
如果你想要自定义转换,你可以这样做:
@InverseMethod("convertToPrice")
public String convertFromPrice(Object key, int price) {
//...
}
public int convertToPrice(Object key, String text) {
//...
}
然后您将在表达式中传递价格对象:
<EditText android:text="@={shipper.convertFromPrice(priceKey, shipper.price)}" .../>
我会简化转换方法,使它们可在我的整个应用程序中重复使用,只需将整数转换为字符串并返回:
public class Converters {
@InverseMethod("fromPrice")
public static final int toPrice(String text) {
//...
}
public static final String fromPrice(int price) {
//...
}
}
然后表达式将是:
<EditText android:text="@={Converters.fromPrice(shipper.price[priceKey])}" .../>