Android数据绑定在使用View的'android:tag'属性时无法工作

9

我正在尝试在我的项目中使用新的Android数据绑定,但是当我尝试将“android:tag”属性设置为某些自定义变量时,我遇到了错误。

我的menu_item.xml文件:

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

    <data>

        <variable
            name="menuItem"
            type="com.example.MenuItem" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:tag="@{menuItem}"
        tools:ignore="UseCompoundDrawables">

        <!--suppress AndroidUnknownAttribute -->
        <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:imageResource="@{menuItem.itemType.drawableId}" />

        <TextView
            android:id="@+id/displayName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{menuItem.itemType.displayNameId}" />

    </LinearLayout>
</layout>

我的 MenuItem 类:

public class MenuItem {

    public final ItemType itemType;

    public MenuItem(ItemType itemType) {
        this.itemType = itemType;
    }

}

生成的MenyItemBinding.java部分代码:

public MenuItemBinding(View root) {
        super(root, 0);
        final Object[] bindings = mapBindings(root, 3, sIncludes, sViewsWithIds);
        this.displayName = (android.widget.TextView) bindings[2];
        this.displayName.setTag(null);
        this.icon = (android.widget.ImageView) bindings[1];
        this.icon.setTag(null);
        this.mboundView0 = (android.widget.LinearLayout) bindings[0];
        this.mboundView0.setTag(root.getResources().getString(com.myApp.R.string.@{menuItem}));
        setRootTag(root);
        invalidateAll();
    }

错误出现在生成的类中,当尝试设置绑定视图的标记时。

有什么想法可以解决这个问题吗?最好不要使用自定义LinearLayout来支持此功能。


你能打印LogCat吗?我从未直接在xml中设置标签,甚至不知道这是可能的。但是如果你尝试将MenuItem设置为标签,我猜Android会抱怨因为它找不到一个空构造函数来创建MenuItem。 - Gordak
这是一个编译时错误。请参见上面生成的类的部分。更具体地说,错误出现在“this.mboundView0.setTag(root.getResources().getString(com.myApp.R.string.@{menuItem}));”上。关于空构造函数 - 我同时将menuItem用于TextView和ImageView,但没有任何投诉。 - marius bardan
1个回答

17

这是一个错误。我们没有尝试过数据绑定标签,主要因为标签是特殊的。

当针对低于ICS的设备时,Android数据绑定接管布局最外层元素的标签。这个标签通常用于绑定生命周期,并被DataBindingUtil.findBinding()DataBindingUtil.getBinding()使用。

因此,由于数据绑定不适用于标签,唯一的解决办法是不向LinearLayout提供标签,或者提供固定标签或资源字符串。如果您的目标是ICS及以上版本,则在绑定布局后重新分配标签是有效的:

MenuItemBinding binding = MenuItemBinding.inflate(layoutInflater);
binding.getRoot().setTag(menuItem);

您也可以为新属性创建一个BindingAdapter:

@BindingAdapter("specialTag")
public static void setSpecialTag(View view, Object value) {
    view.setTag(value);
}

然后在您的布局中使用它:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    app:specialTag="@{menuItem}"
    tools:ignore="UseCompoundDrawables"/>

这将允许您使用findViewByTag()和其他您期望的功能。

但是,如果您的目标是蜂巢和早期设备,则此方法将无法使用。无法解决此问题。您可能会尝试像这样做些事情:

@BindingAdapter("specialTag")
public static void setSpecialTag(View view, Object value) {
    view.setTag(R.id.app_tag, value);
}

使用那种方法,您将无法使用 findViewByTag ,但是当您使用视图时,它将存储任何您想要的值。但是,我们不使用带有Honeycomb和早期版本的ID标记的原因是在使用ID标记时会出现内存泄漏,因此不要这样做。

我希望这可以帮助到您。我将在内部提交错误报告以支持数据绑定android:tags。


有一件事我从文档中没搞明白 - 你在这里也提到了。你把 'setSpecialTag' 方法放在哪里?我认为需要一个自定义的 LinearLayout 来绑定新属性。 - marius bardan
@BindingAdapter注解可以让数据绑定框架找到方法,这些静态方法可以放置在代码的任何地方。我们建议将这些方法与特殊类关联起来。在这种情况下,你只需要使用“app:tag”属性即可自动调用setTag方法,因为“tag”匹配了setTag方法 -- 你不需要任何BindingAdapter。 - George Mount
1
那是一个漏洞!感谢你发现了它。 - George Mount
我想知道它是如何知道@BindingAdapter方法的位置的?你不会在布局中导入静态类,对吧。这个工具类必须位于与ViewModel相同的包中吗,以便通过反射找到它? - Konrad Morawski
处理是作为编译阶段的注解处理器的一部分完成的。它比反射更了解表达式中使用的类型,这是它的优点。特定的包不重要,类也不重要。 - George Mount
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接