Unknown data binding attribute: onLongClick - Attribute exists and works

Viewed 1694

In my data binding layouts, I set long click listeners via:

android:onLongClick="@{ ..binding expression.. }"

The code runs as expected, but the android:onLongClick attribute is flagged as 'unknown' in the xml file. Additionally, there is no auto-complete for it.

The binding adapter for this attribute is included with the data binding library in ViewBindingAdapter.java.

3 Answers

As said here you can use: android:onLongClick="@{() -> handler.onLongClicked()}"

but if you want to remove warning you can use below code instead of above:

app:onLongClickListener="@{() -> handler.onLongClicked()}"

if you use app:onLongClickListener data binding will find setOnLongClickListener in the View class and will use that method

There is a difference between onLongClickListener and onLongClick : We have a method in view called setOnLongClickListener but we do not have a method like this: setOnLongClick and when you use an attribute atr in data binding that has a method like setAtr data binding will find and use that method automatically not needing any adapter. Thus onLongClickListener do not need any adapter (if there is an adapter it will be used instead of setOnLongClickListener) but onLongClick always needs adapter.

Thanks to Bahman for the helpful answer. Here's some more details and options.

If one uses the native xml binding app:onLongClickListener then the viewModel must return Boolean or android compilation crashes with cannot generate view binders java.lang.StackOverflowError

So this crashes the compiler: app:onLongClickListener="@{() -> viewModel.onLongClickRowNoReturn()}" assuming the viewModel method does not return Boolean. If it returns a boolean it works. The Boolean is required by View.OnLongClickListener see View.OnLongClickListener

Alternatively we can use our own custom adapter

@BindingAdapter("onLongClick")
fun setOnLongClickListener(view: View, listener: Runnable) {
    view.setOnLongClickListener { listener.run(); true }
}

XML: app:onLongClick="@{() -> viewModel.onLongClickRowNoReturn()}"

Here's the docs as Bahman also linked, though they are not very informative regarding this issue.

My viewModel example:

    override fun onLongClickRow():Boolean {
        Toast.makeText(context, "LongClick", Toast.LENGTH_SHORT).show()
        return true
    }
    override fun onLongClickRowNoReturn() {
        Toast.makeText(context, "LongClick without return", Toast.LENGTH_SHORT).show()
    }

onLongClick and onLongClickListener do the exact same thing because there is a BindingMethod that connects onLongClick to setOnLongClickListener in ViewBindingAdapter.java.

It seems like the IDE just complains about any android: prefixed attributes that don't exist in the framework. This is why it doesn't complain about the app: versions. However, they are not always freely interchangeable because for example android:text does some performance optimizations under the hood whereas app:text would just call setText directly.

Related