有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java BindingAdapter未被识别为适用于具有泛型的属性

ObservableList<Subclass>@BindingAdapter声明与ObservableList<Baseclass>匹配的行为非常奇怪


我正在MVVM环境下试用安卓数据绑定库,偶然发现了一个我不理解的行为,到目前为止还没有找到任何资源

设置:

Min SDK: 19
Target SDK: 26
Build Tools Version: 27.0.1

我想通过使用自定义绑定适配器将安卓.databinding.ObservableList<Model>绑定到RecyclerView,该适配器获取列表,将其包装到泛型RecyclerView.Adapter并将其分配给RecyclerView

我的绑定适配器设置如下:

@BindingAdapter({"items"})
public static void bindAdapterWithDefaultBinder(@NonNull RecyclerView recyclerView,
                                                @Nullable ObservableList<Model> items){
... implementation ...
}

My viewmodel具有以下属性:

public final ObservableList<Repo> repos = new ObservableArrayList<>();

Repo在本例中,实现接口Model

布局文件包含

<安卓.support.v7.widget.RecyclerView
            安卓:layout_width="match_parent"
            安卓:layout_height="match_parent"
            app:items="@{vm.repos}"
            />

编译时,我收到以下错误:

Error:Gradle: Execution failed for task ':app:compileDebugJavaWithJavac'.
> java.lang.RuntimeException: Found data binding errors.
  ****/ data binding error ****msg:Cannot find the setter for attribute 'app:items' with parameter type 安卓.databinding.ObservableList<_my-package-name_.Repo> on 安卓.support.v7.widget.RecyclerView.

所以我认为这与类型Repo在绑定转换器声明中没有被识别为Model的有效替代物有关。奇怪,但确实如此-如果我将声明更改为使用ObservableList<Repo> items,那么代码可以很好地编译并工作。但这对我来说不是一个可行的解决方案,因为这将迫使我为我打算使用的每个模型或视图模型类型编写一个绑定适配器。因此,经过一些实验,我找到了一个不同的解决方案:

    <安卓.support.v7.widget.RecyclerView
            安卓:layout_width="match_parent"
            安卓:layout_height="match_parent"
            app:items="@{(Object)vm.repos}"
            />

现在,该解决方案使用ObservableList<Model> items适配器声明进行编译,并在运行时正确传播所有更改事件。因此,基本上我将ObservableList<Repo>转换为Object,并将其解释为与适配器定义匹配。什么

请记住,所有这些都发生在编译时,代码生成器知道确切的类型,因此不会发生类型擦除

因此,我的问题顺序如下:

  • 为什么第一次实现失败了
  • 为什么通过强制转换来解决问题
  • 既然这看起来像一个丑陋的黑客对我来说-什么是正确的方式来实现这种行为

附言:

关于这个问题的更多内容,我基本上是通过这个示例代码工作的,我发现这是一个很好的灵感来源:https://github.com/manas-chaudhari/安卓-mvvm/blob/master/Documentation/GettingStarted.md

但是请注意,作者如何厚颜无耻地将所有模型对象“强制转换”为基类类型,以避免这个确切的问题here


共 (1) 个答案

  1. # 1 楼答案

    我认为你应该把牙套取下来,这样做:

    @BindingAdapter("items")   
    public static void bindAdapterWithDefaultBinder(@NonNull RecyclerView recyclerView, @Nullable ObservableList<Model> items) {
    ... implementation ...
    }