如何使用android数据绑定绑定接口?

时间:2017-06-01 08:08:57

标签: android data-binding

我的情况是我有一个片段,其文本字段将由X1Object或X2Object填充,它们都实现了接口IXObject并扩展了Android DataBinding库提供的BaseObservable类,但包含其他不同的字段和行为。 IXObject包含getter和setter的方法。

public interface IXObject {
    void setName(String name);
    String getName();
}

public class X1Object extends BaseObservable implements IXObject {
    private String name;

    @Override
    @Bindable
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }
}

public class X2Object extends BaseObservable implements IXObject {...}

然后我尝试使用Android DataBinding为片段使用单个布局文件。布局如下所示:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>
    <variable name="xObject" type="com.test.x.model.IXObject"/>
</data>

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{xObject.name}"/>

</LinearLayout>
</layout>

在片段类中,我正在应用绑定:

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    MyFragmentBinding binding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false);

    View view = binding.getRoot();

    IXObject xobj = new X1Object();
    binding.setXObject(xobject);

    return view;
}

不幸的是,使用IXObject作为数据绑定引用,从不调用BaseObservable类中的方法“addOnPropertyChangedCallback”。

直接使用X1Object在布局文件和绑定类中进行绑定,一切都很完美。

您能帮助我实现使用界面进行绑定的目标吗?

谢谢。

4 个答案:

答案 0 :(得分:2)

我也找不到使用界面的方法,但我认为你可以像这样使用Abstract类。

public abstract class IXObject extends BaseObservable {
    public abstract void setName(String name);

    @Bindable
    public abstract String getName();
}

public class X1Object extends IXObject {
    private String name;

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }
}

final IXObject xobj = new X1Object();
xobj.setName("nguyen");
binding.setXObject(xobj);

答案 1 :(得分:1)

在布局文件中声明变量时,必须从字面上接受它。接口不是对象。我知道Java支持通用的内联对象,您可以在其中声明接口,就好像它是一个对象一样,但是通常它们不是对象。

因此,当您说到布局文件使用接口类型的变量时,由于它不是对象,因此它实际上不能做很多事情。

您会注意到并讨厌Android数据绑定的一件事是它无法推断类型。因此,如果您尝试使用实现类来设置变量,但希望通过接口来实现它,那么您将没有任何运气。

您需要指定将使用的类,而不是这些类继承自的接口。另一个答案指出,如果您的基类具有必要的方法,则可以利用基类。

另外请注意,您只需将绑定放在私有成员变量上,它仍然会自动通过getter和setter方法。

您唯一可以做的另一件事是创建一个适配器,该适配器使用接口或您的接口,甚至使用Any强制转换,并为您设置名称。在您已经成长的适配器类中,还需要一个适配器,但是至少他们是直接这样做的。

答案 2 :(得分:0)

我想我找到了问题的根源。根据数据绑定文档,布局中设置的每个变量都必须实现Observable接口:

  

在编译时检查变量类型,因此如果变量实现了Observable或者是一个可观察的集合,那么它应该反映在类型中。如果变量是没有实现Observable *接口的基类或接口,则不会观察到变量!

因此没有机会使用界面。我必须使用上面答案中提到的抽象类。

答案 3 :(得分:0)

只需在界面内使用@get:Bindable而不是@Bindable。 而是改用LiveData:https://developer.android.com/topic/libraries/data-binding/architecture