Hi im a begginer on Android development. I knew basic core java. So i have a question on this particular code:
button.setOnClickListener(new View.OnClickListener()
{
#Override public void onClick(View v)
{
// do something when the button is clicked
}
});
I know that this is anonymous class and OnClickListener is an interface. But what i dont understand is the onClick(View v) method, v is the button that was clicked but under the hood how was this method AUTOMATICALLY executed? I mean isnt that to be able to call a method you must first create an object then a method beside it? I just need to understand this concept, thank you.
In simple words when you create a Button object it has some listener objects:
Example:
class Button extends View{
private OnClickListener clickListener;
public void setOnClickListener(OnClickListener clickListener){
this.clickListener = clickListener;
}
}
when you call this:
button.setOnClickListener();
basically you assign the value to clickListener in Button class and then each time you click the button it triggers
clickListener.onClick(this)
and perform your defined stuff.
Your listener is provided to the Button object, and by clicking the button, the Android framework will try to invoke the OnClickListener (if any) by calling the onClick method you provide.
So it is not really automatically. Your action triggers the click, and Android framework calls your onClick.
I have 3 buttons in a fragment that I want to use the same click event. How can this be achieved within a fragment?
XML
<Button
android:id="#+id/btn_1"
android:onClick="btnClick_DoSomething"
android:text="#string/one"/>
<Button
android:id="#+id/btn_2"
android:onClick="btnClick_DoSomething"
android:text="#string/two"/>
<Button
android:id="#+id/btn_3"
android:onClick="btnClick_DoSomething"
android:text="#string/three"/>
Java
#Override
public void btnClick_DoSomething(View v) {
}
Error
#Override (within the fragment Java class) becomes underlined in red and the following error is returned
Annontations are not allowed here
I want the onClick event to be the same for all 3 buttons
You dont need to write #Override annotation as you are not overriding the method. Just use
public void btnClick_DoSomething(View v) {
}
You will get a callback in this method at runtime.
you simply don't do it in XML, do it in Java instead:
<Button
android:id="#+id/btn_1"
android:text="#string/one"/>
<Button
android:id="#+id/btn_2"
android:text="#string/two"/>
<Button
android:id="#+id/btn_3"
android:text="#string/three"/>
then...
private final OnClickListener onClick = new OnClickListener(){
#Override
public void onClick(View view){
switch(view.getId()){
... cases...
}
}
somewhere initialising the views you do:
fragmentView.findViewById(R.id.btn_1).setOnClickListener(onClick);
fragmentView.findViewById(R.id.btn_2).setOnClickListener(onClick);
fragmentView.findViewById(R.id.btn_3).setOnClickListener(onClick);
}
What method are you trying to override? Do any of the parent classes have a method btnClick_DoSomething? You do not need to override anything when setting a click listener from a Layout XML. Just ensure that a method of the same name with a void return type and a View as its only argument exists in the activity class that will use this layout
The general way to distinguish clicks from different Views in the same onClick handler is to identify them by id
public void btnClick_DoSomething(View v){
switch(v.getId()){
case R.id.btn_1:
// handle click from button 1
break;
case R.id.btn_2:
// handle click from button 2
break;
case R.id.btn_3:
// handle click from button 3
break;
}
}
There are some misunderstandings here. To override a Click event, your Fragment need to implement the View.OnClickListener interface like this:
public class YourFragment extends Fragment implements View.OnClickListener{
#Override
public void onClick(View v) {
}
}
Note that the name of the method must be onCLick, must return void and recives a View as a parameter to be overrided from the interface. In this case you need to set a Listener to each button in your fragment:
btn1 = (Button) view.findViewById(R.id.btn_1);
btn1.setOnClickListener(this);
Inside this method you can control which object was clicked by it´s ID
#Override
public void onClick(View v) {
int id = v.getId();
switch(v.getId()){
case R.id.btn_1:
// handle click from button 1
break;
case R.id.btn_2:
// handle click from button 2
break;
case R.id.btn_3:
// handle click from button 3
break;
}
}
Or, you don't need to override the method, so remove the anotation that will work's fine :
public void btnClick_DoSomething(View v) {
switch(v.getId()){
case R.id.btn_1:
// handle click from button 1
break;
case R.id.btn_2:
// handle click from button 2
break;
case R.id.btn_3:
// handle click from button 3
break;
}
}
Instead of declaring the onClick method in the xml layout file, you could have your Fragment implement View.onClickListener interface, override onClick(), and set all 3 buttons onClickListener like this btn.setOnClickListener(this). Put the behavior you want for all 3 buttons in onClick(). All 3 will have the same behavior (unless you check which button the event came from in onClick()).
btn_Login.setOnClickListener(this);
In android studio.
I've seen this in countless places. What does this mean? I know how this operates but what is the listener called then?
This example is from: Link
Suppose that you have 16 Buttons and every button has setOnclicklistener this means that you are creating many repetitions of similar code to this in your class. And that makes your code ugly, also this is not the efficient way to write your code. So to make your code efficient you have to implement OnClickListener() on your activity and then for each button use buttonX.setOnClickListener(this). Now use the override onClick method. In this method, you can use either the switch case block or if-else to identify which button is pressed. So in the onClick method you just have to give ids of the button.
Implement OnClickListener in Activity
public class MyActivity extends Activity implements View.OnClickListener {
}
For each button use this:
buttonX.setOnClickListener(this);
After this implement override the onClick method
#Override
public void onClick(View view) {
switch(view.getId){
case R.id.buttonX:
// Do something
break;
}
in that example its defined like this
private Button btn_Login;
Button is a class
onClickListener is a listener, to set the listener he is using setOnClickListener method.
From the next time if u need to those kind of clarifications don't post in a separate thread, add a comment in that question itself.
Thank You #august alsina
It is a listener that helps to specify the events to occur on click of a widget.
When your class implement View.OnClickListener, you can defined your click of each button in method public void onClick(View v). Keyword this refer to the method onclick. It is good to use this way when there are a lot of button in your class file. You can define following code On Create method:
button1.setOnClickListener(this);
button2.setOnClickListener(this);
and define its definition oncreate method. For example:
public void onClick(View v){
int id= v.getId();
switch (id){
case R.id.btn1: {
//do sth
//break;
}
case R.id.btn2: {
//do sth
//break;
}
...
}
}
In layman's terms
By writing btn_Login.setOnClickListener(this);
whenever btn_login will be pressed program will go to onclick method public void onClick(View v)
and then you can write in the method what you want to do when button is pressed
Suppose we have an Activity with a lot of views on which OnClickListener is to be registered.
The most common way to implement this is to let the Activity-Subclass implement the OnClickListener, something like this:
public class ActivityMain extends Activity implements View.OnClickListener
{
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
The way I like to implement it is to create a private class inside the Activity-Subclass and let that inner class implement the OnClickListener:
public class ActivityMain extends Activity implements View.OnClickListener
{
private class ClickListener implements View.OnClickListener
{
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
}
This way the code seems more organized and easy to maintain.
Moreover, talking about "Is-a", "Has-a" relationships, the latter seems to be a good practice because now the Activity-Subclass would have a "Has-a" relationship with the ClickListener.
While in the former method we would be saying that Our Activity-Subclass "Is-a" ClickListener, which ain't completely true.
Note that, I am not concerned with the memory overhead the latter would cause.
Also, adding onClick tag in xml is completely out of question.
So, what really is the best way to implement a ClickListener?
Please don't suggest any libraries like RoboGuice or ButterKnife etc.
UPDATE:
I would like to share the approach I finally adopted.
I directly implement the listener in Activity/Fragment.
As far as OOP design is concerned. The "HAS-A" approach doesn't offers any practical benefits and even takes up more memory. Considering the amount of nested classes (and the memory overhead) we will be creating for every similar listener we implement, this approach should clearly be avoided.
First, there is no best practice defined by Android regarding registering click listeners. It totally depends on your use case.
Implementing the View.OnClickListener interface to Activity is the way to go. As Android strongly recommends interface implementation over and over again whether it is an Activity or Fragment.
Now as you described :
public class ActivityMain extends Activity implements View.OnClickListener
{
private class ClickListener implements View.OnClickListener
{
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
}
This is your approach. Now it is your way of implementation and there is nothing wrong with this if you are not concerned with memory overhead. But what's the benefit of creating the inner class and implementing the View.OnClickListener if you can simply implement that in the main class which can also lead to the code clarity and simplicity that you need.
So it just a discussion rather getting the best possible solution of implementing the View.OnClickListener because if you go with the practical point of everyone, you will go for a solution which is simple and memory efficient.
So I would prefer the conventional way. It keeps things simple and efficient. Check the code below:
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
P.S : Your approach will definitely increase lines of code :P ;)
First of all lets get the basics clear here..
By implementing an Interface, your class doesn't become that.. like you said:
"Our Activity-Subclass "Is-a" ClickListener, which ain't completely true."
Your class can only have "Is-a" relationship if it extends, in this case an Activity. Implementing an interface means that it can behave like what interface has set its contract.
An Example:
class Peter extends Human .. means Peter is a Human..
class Peter can also implement programmer, musician, husband etc
means Peter can behave as the above.
As for best practice, you could make an entirely separate class which implements OnClickListener like this:
class MyListener implements View.OnClickListener{
#Override
public void onClick(View view) {
// do whatever you want here based on the view being passed
}
}
And in your main Activity you could instantiate MyListener and call onClick() and pass your view in it:
MyListener listener = new MyListener();
Button b = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button);
listener.onClick(button);
}
I use button.setOnClickListener(this); where my Activity implements View.OnClickListener, and then get the ID of the Button in a separate method. See below for an example:
public class MyActivity extends ActionBarActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.YOUR_LAYOUT);
...
Button myFirstButton = (Button) findViewById(R.id.YOUR_FIRST_BUTTON);
myFirstButton.setOnClickListener(this);
Button mySecondButton = (Button) findViewById(R.id.YOUR_SECOND_BUTTON);
mySecondButton.setOnClickListener(this);
...
}
...
#Override
public void onClick(View v) {
Button b = (Button) v;
switch(b.getId()) {
case R.id.YOUR_FIRST_BUTTON:
// Do something
break;
case R.id.YOUR_SECOND_BUTTON:
// Do something
break;
...
}
}
...
}
Here you can create a btnClickListner object and after that you will call that btnCLickLisner object when ever you want to perform the onCLieck actions for buttons..
Let us assume, in my activity i have a 5 to 10 buttons and writing each button separate onclick listner is bad idea. So to over come this,we can use like below..
register your buttons
Button button1 = (Button)findViewById(R.id.button1);
Button button2 = (Button)findViewById(R.id.button2);
Button button3 = (Button)findViewById(R.id.button3);
Button button4 = (Button)findViewById(R.id.button4);
Button button5 = (Button)findViewById(R.id.button5);
Here i am setting the onclick listner to my buttons after click
button1.setOnClickListener(btnClickListner);
button2.setOnClickListener(btnClickListner);
button3.setOnClickListener(btnClickListner);
button4.setOnClickListener(btnClickListner);
button5.setOnClickListener(btnClickListner);
Here is the btnClick Listner implementation
View.OnClickListener btnClickListner = new OnClickListener()
{
#Override
public void onClick( View v )
{
// TODO Auto-generated method stub
if( button1.getId() == v.getId() )
{
//Do Button1 click operations here
}
else if( button2.getId() == v.getId() )
{
// Do Button2 click operations here
}
else if( button3.getId() == v.getId() )
{
// Do Button3 click operations here
}
else if( button4.getId() == v.getId() )
{
// Do Button4 click operations here
}
else if( button5.getId() == v.getId() )
{
// Do Button5 click operations here
}
}
}
I have found using Butterknife makes for clean code. And because it uses code generation (not reflections) it has little performance overhead.
public class ActivityMain extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
}
#OnClick(R.id.button_foo)
void onFoodClicked() {
// Do some foo
}
#OnClick(R.id.button_bar)
void onBarClicked() {
// do some bar
}
}
For this particular case I'd say that maintain a single instance of a OnClickListener is the best approach for you. You will have a "Has-a" relationship and won't need to create several instances since you are handling the behavior using the view id in the onClick(View view) callback.
public class ActivityMain extends Activity implements View.OnClickListener {
private View.OnClickListener mClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
//handle multiple view click events
}
}
};
}
Your ClickListener is an inner non-static class the coupling of this 'has-a' is no different than if your class Activity implemented View.OnClickListener. This is because your inner ClickListener requires an instance of ActivityMain and really can't be reused. I would argue that you're over engineering and aren't actually gaining anything.
EDIT: To answer your question I like to have anonymous View.OnClickListener for each widget. I think this creates the best separation of logic. I also have methods like setupHelloWorldTextView(TextView helloWorldTextView); where I put all my logic related to that widget.
First approach is better than the other because thats why View.OnClickListener is an Interface instead of an abstract class. besides the later might leak in various situations since you are using a non-static inner class.
A small remark to this, and maybe a little bit of topic.
What, if we not just implement OnClickListener and we have a bunch of other Listeners / Callback to implement. In my Opinion it will get messy to implement all of these in the class instead of using anonymous classes / lambda. It is hard to remember wich method belongs to which interface.
So if we have to implement an interface (in this case OnClickListener) multiple times it my be a good solution to implement on class base and use the switch/case.
But if we have to implement multiple interfaces it may be a good solution to use anonymous classes / lambda
simply you using like not implements subclass or not handle a click event just do like this way .
android.view.View.OnClickListener method_name = new android.view.View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// put your code .
}
};
and handle click event into button ya any type of click event like
button_name.setOnClickListener(method_name);
its work very simply
Thanks
public class ProfileDetail extends AppCompatActivity implements View.OnClickListener {
TextView tv_address, tv_plan;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile_detail);
tv_address = findViewById(R.id.tv_address);
tv_plan = findViewById(R.id.tv_plan);
tv_address.setOnClickListener(this);
tv_plan.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_plan:
startActivity(new Intent(getApplicationContext(),PlanActivity.class));
break;
case R.id.tv_address:
startActivity(new Intent(getApplicationContext(),AddressActivity.class));
break;
}
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Chronometer chronometer;
private Button startButton;
private Button stopButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chronometer = findViewById(R.id.chronometer);
startButton =findViewById(R.id.startBtn);
stopButton = findViewById(R.id.stopBtn);
startButton.setOnClickListener(this);
stopButton.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.startBtn:
chronometer.start();
break;
case R.id.stopBtn:`
chronometer.stop();
break;
}
}
}
It really depends on what you want to achieve. If you have e.g. a complex functionality with threading, dependencies, etc., I personally like to decouple it completely from the Activity into a separate class XyzAction, that does the heavy stuff, knows about certain Invokers and returns them results, if needed. My Invokers are basically objects, that implement OnClick/OnTouch/etc.Listeners and bind themselves to needed actions. E.g. there could be a LoginInvoker implementing OnClickListener for a Button and an ImageView and also a generic ActionListener that gets invoked when a MenuItem is clicked. The Invoker has update methods for showing progress to the user and the result of the bound action. The action posts updates to its Invokers and can be garbage collected, if all of them die, because it has no connection to the UI.
For less complex actions, I couple them directly to the Android component (i.e. Activity/Feagment/View) and also call them Actions, with the big difference of them implementing the UI callbacks directly.
In both cases I declare the actions as members, so I can see on a quick glance what specific actions the Android component supports.
If there's something trivial like "show a Toast if button is pressed", I use anonymous inner classes for the UI callbacks, because you normally don't care that much about them with regards to maintainability.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button north,south,east,west;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
north.setOnClickListener(this);
south.setOnClickListener(this);
east.setOnClickListener(this);
west.setOnClickListener(this);
}
private void init(){
north = findViewById(R.id.north);
south = findViewById(R.id.south);
east = findViewById(R.id.east);
west = findViewById(R.id.west);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.north:
Toast.makeText(MainActivity.this,"NORTH",Toast.LENGTH_SHORT).show();
break;
case R.id.south:
Toast.makeText(MainActivity.this,"SOUTH",Toast.LENGTH_SHORT).show();
break;
case R.id.east:
Toast.makeText(MainActivity.this,"EAST",Toast.LENGTH_SHORT).show();
break;
case R.id.west:
Toast.makeText(MainActivity.this,"WEST",Toast.LENGTH_SHORT).show();
break;
}
}
}
I have an activity which does all the setup process, i.e. creating the initial view and the OnClickListener, which then at some point creates an object passing the activity and OnClickListener as parameters. The object then does it's own setup, changing to view and setting TableRows with the OnClickListener. I run into the issue that when ever I click on one of the Rows, it seems OnClick(View v) is not called. The code seems solid but I'm either missing something or my implementation simply wont work. Any help would be appreciated.
public class MyActivity extends Activity {
private Object mObject;
private TextView textView;
private OnClickListener mListener = new OnClickListener() {
public void onClick(View v) {
switch(v.getId()) {
case R.someId:
mObject = new Object(MyActivity.this, mListener);
break;
case R.id.table_row:
doSomething();
break;
}
}
}
textView = (TextView)findViewById(R.id.someId);
textView.setOnClickListener(mListener);
}
public class Object {
private Activity mActivity;
private OnClickListener mListener;
private TableRow tableRow;
public Object(Activity a, OnClickListener o) {
mActivity = a;
mListener = o;
mActivity.setContentView(R.layout.layout);
tableRow = (TableRow)findViewById(R.id.table_row);
tableRow.setOnClickListener(mListener)
}
}
Edited code as suggested:
public class MyActivity extends Activity implements OnClickListener{
private Object mObject;
private TextView textView;
#override
public void onClick(View v) {
switch(v.getId()) {
case R.someId:
mObject = new Object(MyActivity.this, mListener);
break;
case R.id.table_row:
doSomething();
break;
}
}
}
I omitted the Object class because with the above code onClick is not called without setting the OnClickListener with view.setOnClickListener(this); This also does not allow me to pass the Listener itself as a parameter, as far as I know.
at first glance, it appears that you aren't attaching that listener to anything in the first place... What element gets to call your listener the first time around? Your Object gets created when someone calls your Listener, but no one's calling it :)
Btw, you can implement onClickListener at the start of your Activity class creation, in which case, everything becomes clickable and you can then just listen for the id of what got clicked and react accordingly (rather than adding listeners, one at a time, to everything on the screen)... obviously this approach makes more sense when you have a bunch of clickable items (like a Battleship grid), rather than just a couple of buttons.
EDIT with example
public class MyGame extends Activity implements OnClickListener{
//... onCreate and all that jazz
//.. here you capture anything and everything getting clicked
public void onClick(View v){
switch (v.getId()){
case R.id.myClickableObj1:
//react to obj1 being clicked
break;
case R.id.myClickableObj2:
//etc. etc.
break;
}
}
}