通用@BindingConversion不起作用

时间:2016-03-07 16:13:12

标签: android generics android-databinding

为什么不能在android数据绑定库中定义通用绑定转换?

@BindingConversion
public static <T> T convertMyClass(MyClass<T> obj) {
    return obj.get();
}

使用此方法我收到can not find the setter for attribute 'android:text' with parameter type com.example.MyClass<java.lang.String>错误。定义显式类型可以正常工作。

我试图找到ObservableField<T>转换的方式,但没有成功。有谁知道这是怎么回事?有什么我做错了吗?

1 个答案:

答案 0 :(得分:2)

用两个词来说:type erasure

泛型是一把双刃剑,它削减了类型系统的一些运行时功能,以换取编译时间检查。您告诉编译器重写代码以使这些类型转换“正常工作”。权衡是它必须将类似“T”的泛型类引用转换为“对象”。所以编译后你的方法的签名是

Object convertMyClass(MyClass)

数据绑定系统正在寻找返回类型“String”。所以甚至不考虑你的方法。

数据绑定系统可能会变得更聪明,能够识别你的BindingConversion,但我不会屏住呼吸这个功能。

这是一些说明类型擦除的bash。

$ echo 'public class A{ public <T> T deRef(java.util.concurrent.atomic.AtomicReference<T> atom) {return atom.get();} }' >A.java
$ javac A.java
$ groovy -e 'println A.class.getMethod("deRef", java.util.concurrent.atomic.AtomicReference.class)'
public java.lang.Object A.deRef(java.util.concurrent.atomic.AtomicReference)

最后一行输出是泛型方法的方法签名。

解决方法是将MyClass子类化为具有特定参数化的子类,如下所示:

public class MyStringClass extends MyClass<String> {
  @Override
  public String get() {
    return super.get();
  }
  @BindingConversion
  public static String convertMyClass(MyStringClass obj) {
    return obj.get();
  }
}

关于ObservableField,它不需要BindingConversion机制,因为数据绑定库在java代码中引用它,因此编译时泛型检查可以完成匹配类型的工作。