通用@BindingConversion 不起作用

Generic @BindingConversion doesn't work

为什么无法在 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> 转换的方式,但没有成功。有谁知道这是怎么回事?我做错了什么吗?

两个词:type erasure.

泛型是一把双刃剑,它切断了类型系统的一些 运行 时间能力,以换取编译时检查。您告诉编译器重写代码以进行这些类型转换 "just work." 代价是它必须将通用 class 引用(如 "T" 转换为 "Object"。所以编译后你的方法的签名是

Object convertMyClass(MyClass)

数据绑定系统正在寻找 return 类型 "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)

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

一种变通方法是使用特定参数化子class 子class 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 代码中引用它,因此编译时泛型检查会完成匹配类型的工作向上。