Databinding onclick listener on button

Viewed 8910

trying to understand data binding, not getting it though. Any help appreciated.

what i need is all together my custom method call "setOnClick(User user)" on click of the button. I just want understand Binding Adapters Concepts.

Execution failed for task ':databinding:compileDebugJavaWithJavac'. android.databinding.tool.util.LoggedErrorException: Found data binding errors. ****/ data binding error ****msg:cannot find method setOnClick() in class com.locale.databinding.MyAdapter file:/Users/svernekar003/Documents/GitHub/RxDagger2Demo/databinding/src/main/res/layout/activity_main.xml loc:61:35 - 61:61 ****\ data binding error ****

sample code.

activity_main.xml

<?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="user"
        type="com.locale.databinding.User"></variable>

    <variable
        name="myClickHandler"
        type="com.locale.databinding.MyAdapter"></variable>
</data>

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.locale.svernekar.databinding.MainActivity">

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:text="@{user.name}"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/last_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:text="@{user.lastName}"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="@+id/name"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.502" />

    <ViewStub
        android:id="@+id/view_stub"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:inflatedId="@+id/inflate_id"
        android:layout="@layout/view_stub_sample" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:onClick="@{()->myClickHandler.setOnClick(user)}"
        android:text="Change Data"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/last_name" />

</android.support.constraint.ConstraintLayout>

MyAdapter.java

public class MyAdapter {

private User user;

@BindingAdapter("android:onClick")
public static void setOnClick(User user) {

    Log.d("Onclick", "after do long time");
}


@BindingAdapter("android:src")
public static void setImageResource(ImageView imageView, int resource) {
    imageView.setImageResource(resource);
}

public int getId() {
    return android.R.drawable.ic_dialog_dialer;
}
}
2 Answers

Use this

 android:onClick="@{user}"

Because you have created BindingAdapter

@BindingAdapter("android:onClick")
public static void setOnClick(User user) {

    ...
}

Reason

You have created @BindingAdapter of attribute android:onClick so it will work like above.

You're missing an understanding of callbacks here. I suggest doing Google's databinding code lab here:

https://codelabs.developers.google.com/codelabs/android-databinding/index.html

However, we can walk through the solution together.

First, to create a BindingAdapter, you need to specify a view type in the method. So, it should look something like this:

@BindingAdapter("android:onClick")
fun setOnClick(view: View, user: User) {
    Log.d("Onclick", "after do long time")
}

Now, the thing about BindingAdapters is, they are set either when the page loads or when their bound value changes. So, if User is a LiveData, this will work, BUT it won't call when the user clicks- it'll call when the user value is updated. BindingAdapters call when their bound value updates, no matter what the name is. So, the above code is the same as this block:

@BindingAdapter("app:userUpdated")
fun setUserUpdated(view: View, user: User) {
    Log.d("UserUpdated", "after user value is updated")
}

Your onClick binding isn't setting a click listener in this case- it's setting a binding to the "user" field. So, there will be two bindingadapters for onClick- one if you bind a User, and one (system default) if you bind a ClickListener. The XML you have binds to the clicklistener, not the user, so your adapter will never be executed. But even if it was bound correctly, it wouldn't bind on click, because it's not bound that way. To get it to bind on click for the user, you'd need to do something like this:

@BindingAdapter("android:onClick")
fun setOnClick(view: View, user: User) {
    view.setOnClickListener(View.OnClickListener { Log.d("Onclick", "after do long time") })
}
Related