55

I'm trying to bind events with views in xml using DataBinding Library shipped with Android M. I'm following examples from Android Developers and implementing step-by-step. for the view's attributes like visibility,text its working fine but if I try to bind with onclick, it doesn't work as expected. Here's the sample code that I've tried so far:

 <data>
    <import type="android.view.View"/>
    <variable name="user" type="com.example.databinding.User"/>
    <variable name="handlers" type="com.example.databinding.MyHandlers"/>
</data>

 <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}"
    android:visibility="@{user.isFriend ? View.VISIBLE : View.GONE}" />
 <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click Me"
    android:id="@+id/button"
    android:layout_gravity="left"
    android:onClick="@{handlers.onClickFriend}"/>

MainActivity :

  public class MainActivity extends AppCompatActivity {

  User user;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding binding = 
    DataBindingUtil.setContentView(this,R.layout.activity_main);
    user = new User("Pankaj","Kumar",true,true);
    binding.setUser(user);
   }
 }

MyHandlers:

public class MyHandlers {
public void onClickFriend(View view){
    Log.i(MyHandlers.class.getSimpleName(),"Now Friend");
}

public void onClickEnemy(View view){
    Log.i(MyHandlers.class.getSimpleName(),"Now Enemy");
  }
}

I've written only required code to improve readability. Could someone help me on this.

9 Answers 9

107

I think you will need to bind the handlers as well, maybe something like this in onCreate:

MyHandlers handlers = new MyHandlers();
binding.setHandlers(handlers);
Sign up to request clarification or add additional context in comments.

7 Comments

Yep, and if you use your Activity class as Handlers, then you just need to do this: binding.setHandlers(this);
If you have many of the same actions, you can use this library for simplicity - github.com/drstranges/ActionHandler
@dorsz +100 to you! I was searching this for hours!
same goes for presenters if you are using the presenters
This is great! I wish the documentation would outline this better! Thank you for the great answer!
|
63

Many Ways for setting Click

  1. Pass handler to binding.

    ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main); Hander handler = new Handler(); binding.setHandler(handler);

  2. Set clicks (use any of below)

    android:onClick="@{handler::onClickMethodReference}"

OR

android:onClick="@{handler.onClickMethodReference}"

OR

android:onClick="@{() -> handler.onClickLamda()}"

OR

android:onClick="@{(v) -> handler.onClickLamdaWithView(v)}"

OR

android:onClick="@{() -> handler.onClickLamdaWithView(model)}"

See Handler class for understanding.

public class Handler {
    public void onClickMethodReference(View view) {
        //
    }
    public void onClickLamda() {
        //
    }
    public void onClickLamdaWithView(View view) {
        //
    }
    public void onClickLamdaWithObject(Model model) {
        //
    }
}

Note that

  • You can use Method Reference (::) when you have same argument as the attribute onClick.
  • You can pass any object like onClickLamdaWithObject example.
  • If you need to pass View object then just use (v)-> expression.

Further reading

https://developer.android.com/topic/libraries/data-binding/expressions

1 Comment

This is a great answer. Note that only the bottom three with arrow notation are the only ones that lets you ctrl-jump to the code in your handler from the xml (as of mar-19)
16

Use this format in your xml:

android:onClick="@{handlers::onClickFriend}"

Pay attention to the ::, do not worry about the red lines in xml editor, because is currently this is open bug for the Android Studio xml editor.

Where handlers is your variable from data tag:

<data>
    <variable name="handlers" type="com.example.databinding.MyHandlers"/>
</data>

and onClickFriend is your method:

public class MyHandlers {
    public void onClickFriend(View view) {
        Log.i(MyHandlers.class.getSimpleName(),"Now Friend");
    }
}

ADDED

For handle onLongClick in xml add this:

android:onLongClick="@{handlers::onLongClickFriend}"

and add onLongClickFriend method in your ViewModel class:

public class MyHandlers {
    public boolean onLongClickFriend(View view) {
        Log.i(MyHandlers.class.getSimpleName(),"Long clicked Friend");
        return true;
    }
}

ADDED

If you need to show toast message, you can use interface (better variant), or pass context in the MyHandlers class in construction:

public class MyHandlers {
    public boolean onLongClickFriend(View view) {
        Toast.makeText(view.getContext(), "On Long Click Listener", Toast.LENGTH_SHORT).show();
        return true;
    }
}

5 Comments

Hi, do you know how to handle onlongclick events?
It didn't work. Couldn't compile the project. Unknown attribute android:onLongClick.
I am sorry, try change void to boolean in method like this: public boolean onLongClickFriend(View view), and add return true; in the end.
@walkmn how to show toast or pass context in onClickFriend method
we can use view.getContext() method to get the context inside every method so no need to pass it using the constructor.
4

If you're going to use your activity, might as well replace the context object that is automatically binded, otherwise you're wasting the space.

A special variable named context is generated for use in binding expressions as needed. The value for context is the Context from the root View's getContext(). The context variable will be overridden by an explicit variable declaration with that name.

binding.setContext(this);

and

<variable name="context" type="com.example.MyActivity"/>

Note if you just use plain string onClick="someFunc" that's not a databinding functionality at all. That's an older feature that uses a little reflection to find the method on the context.

Comments

4

You should do

android:onClick="@{() -> handlers.onClickFriend()}"

4 Comments

You mean android:onClick="@{(view) -> handlers.onClickFriend}", otherwise that lambda wouldn't match the signature of the onClick event.
@AymenDaoudi more correct it should be android:onClick="@{(view) -> handlers.onClickFriend()}"
The only method that worked for me is from @AlekseyMasny. Tks!
The () -> function() syntax is perfectly valid. Please check the documentation: developer.android.com/topic/libraries/data-binding/…
3

I'm posting this just to cover both ways to achieve this. 1. by Listener binding 2. by method refernce

layout:

<layout...>
<data>

        <variable
            name="handlers"
            type="com.example.databinding.MyPresenter" />
        <variable name="user" type="com.example.databinding.User"/>
</data>

<LinearLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">

    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:text="Using Listener Binding"
            android:onClick="@{() -> handlers.onLisClick(user)}"/>

     <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:text="Using Method Ref"
            android:onClick="@{handlers::onButtonClicked}"/>            

</LinearLayout>
</layout>

Activity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding =
                DataBindingUtil.setContentView(this, R.layout.activity_main);
        MyPresenter presenter = new MyPresenter();
        User user = new User("Alex","RJ")
        binding.setUser(user);
        binding.setHandlers(presenter);
    }

MyPresenter:

public class MyPresenter{

//using listener binding
public void onLisClick(User user){
//do something..
}


//using method reference
public void onButtonClicked(View view){

// do something
}

}

Note:
1.While using method reference the method signature should be same as you would write for any other onClick's method ie public and View as parameter.

2.While using listener binding you have benefit that you can directly pass the Object also if you want and do any operation.

Comments

2

It is not obligatory to create the separate class MyHandlers and call setHandlers for processing android:onClick. You can just use the methods: public void onClickFriend(View view) and public void onClickEnemy(View view) in MainActivity. The activity view:

public class MainActivity extends AppCompatActivity {
    User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding =
                DataBindingUtil.setContentView(this, R.layout.activity_main);
        user = new User("Pankaj", "Kumar", true, true);
        binding.setUser(user);
    }

    public void onClickFriend(View view) {
        Log.i(MyHandlers.class.getSimpleName(), "Now Friend");
    }

    public void onClickEnemy(View view) {
        Log.i(MyHandlers.class.getSimpleName(), "Now Enemy");
    }
}

A layout:

<data>
    <import type="android.view.View"/>
    <variable name="user" type="com.example.databinding.User"/>
</data>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}"
    android:visibility="@{user.isFriend ? View.VISIBLE : View.GONE}" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click Me"
    android:id="@+id/button"
    android:layout_gravity="left"
    android:onClick="@{onClickFriend}"/>

Take a look at the example of using the Data Binding Library for the MVVM pattern: http://cases.azoft.com/mvvm-android-data-binding

3 Comments

well android:onClick="@{onClickFriend}" did not work, but android:onClick="onClickFriend" worked as usual..
This is almost true. You can use your Activity as handlers, and onClick in layout is like android:onClick="@{handlers::onClickFriend}", but you need to bind the handlers in the Activity, like this: binding.setHandlers(this);
Hi, do you know how to handle onlongclick events?
1

I'm posting this because I've had an other situation in which this occurred. If you have two activities referencing to the Layout file and one defines the onclick event and the other doesn't you get the same warning and strangely in the activity where you defined the event.

To check this I recommend finding the usages of the layout file by right clicking on the layout name and press find references. Don't forget to rebuild the app afterwords.

Comments

0

For those who are having trouble in handling long click events:

First create a view in your layout with an id.

<data>
        <variable
            name="tempDesc"
            type="String" />
        <variable
            name="activity"
            type="com.naruto.trangoapp.MainActivity" />
</data>

<TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{(view) -> activity.changeDescText(view)}"
            android:text="@{tempDesc}" />

In your onCreate method use the id name of the view to set any listener:-

binding.textView.setOnLongClickListener(this::onLongClick);

then just create a boolean method with the same name, i.e., onLongClick like this:-

private boolean onLongClick(View l) {
        Toast.makeText(this, "Description", Toast.LENGTH_SHORT).show();
        return true;
    }

That's all!!

Note: You can also set any method to any view in your layout by setting context to the activity variable in your onCreate method:-

binding.setActivity(this);

Then, define and pass the method name with view in your layout to use it in your Activity file. Like I have used a method changeDescText(v) with variable name "activity" for my Textview. Here is my method in Activity file:-

public void changeDescText(View view) {
        binding.setTempDesc("Description Changed");
    }

2 Comments

Do not hold activity reference in your data binding or you will get memory leaks.
@TheLibrarian Do you have a source on that?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.