Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android data binding not working with View 'android:tag' property

Trying to use the new Android Data Binding in my project, but I'm getting an error when trying to set the 'android:tag' property to some custom variable.

My menu_item.xml file:

<?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>

My MenuItem class:

public class MenuItem {

    public final ItemType itemType;

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

}

Part of the genetated 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();
    }

And the error is in the generated class, when trying to set the Tag of the bound view.

Any ideas how to get around this? Preferably, not to use a custom LinearLayout to support this.

like image 522
marius bardan Avatar asked Aug 05 '15 07:08

marius bardan


People also ask

Which is better view binding or data binding in Android?

View binding and data binding both generate binding classes that you can use to reference views directly. However, view binding is intended to handle simpler use cases and provides the following benefits over data binding: Faster compilation: View binding requires no annotation processing, so compile times are faster.

Is Android databinding deprecated?

Recently Android has announced that with Kotlin 1.4. 20, their Android Kotlin Extensions Gradle plugin will be deprecated and will no longer be shipped in the future Kotlin releases. Android Kotlin Extensions plugin brought with it two very cool features : Synthetics let you replace calls to findViewById with kotlinx.


1 Answers

That is a bug. We haven't tried data binding tags, mostly because tags are special.

When targeting devices pre-ICS, Android data binding takes over the tag of the outermost element of the layout. This tag is used for mostly for binding lifecycle and is used by DataBindingUtil.findBinding() and DataBindingUtil.getBinding().

So, since data binding isn't working on tags, the only work-around is to not supply a tag to your LinearLayout or supply a fixed tag or resource string. If you are targeting ICS and above, it is valid to reassign the tag after binding the layout:

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

You can also create a BindingAdapter for a new attribute:

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

and then use it in your layout:

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

This will allow you to use findViewByTag() and all of the other things you expect.

However, this will NOT work if you target Honeycomb and earlier devices. There is no getting around that. You may be tempted to do something like this:

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

You won't be able to use findViewByTag with that approach, but it will store whatever value you want when you use your view. But the reason we don't use ID'd tags with Honeycomb and earlier is that there is a memory leak when using ID'd tags, so don't do it.

I hope this helps. I'll file a bug internally to support data bound android:tags.

like image 139
George Mount Avatar answered Sep 24 '22 12:09

George Mount