Simpler OnClickListener? - android

i am new and learning , i have checked many related posts but still my few following questions are unanswered...[Edited ]the language is java...
following is the way to handle the click on button but can any one explain
1, why i have to declare the anonymous class ,
2, how i know that i have to declare the anonymous class here or any where else could ?
3, why i cannot use simple the btn.setOnClickListener(); why i must have to call anonymous class here ... below line is simple to do the task ...!!
btn.setOnClickListener();
why to make two more lines of code ...? i.e
#override public void onClick (View v) {....}
======================
Button btnCount = (Button) findViewById(R.id.btnCountId);
btnCount.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) { ...... }
});

You are using a Java entity called an "interface".
View.setOnClickListener accepts an object of type "OnClickListener". So you first need to create an object of such a type.
The Object OnClickListener is indeed an interface with one function "onClick", so to create an object of that type you need to implement it (define all the functions in the interface) - in this case, only one.
OnClickListener myClickListener=new OnClickListener() {
#Override // override means you are implementing a function in the interface or a derived class
public void OnClick(View v) {
// the button has been pressed
}
};
and then you can assign it to a view:
myButton.setOnClickListener(myClickListener);
or to many views:
myButton1.setOnClickListener(myClickListener);
myButton2.setOnClickListener(myClickListener);
myButton3.setOnClickListener(myClickListener);
In Java you'll find objects use listener interfaces to communicate events.
Mind that more complex objects use interfaces that can have several methods instead of just one, that's when the simplification you see is not that handy.
Imagine an object "Girl" that has a method "flirt" that you can invoke to ask her for dinner. The Girl will take some time to decide, then communicate one of a lot possible answers with the same interface.
OnGirlFlirtListener myGirlFlirtListener=new OnGirlFlirtListener() {
#Override
public void onGirlSaidYes() {
// invite the girl to have dinner
}
#Override
public void onGirlSaidNo() {
// find another girl or hang with your mates instead
}
#Override
public void onGirlSaidMaybe() {
// ask her later
}
#Override
public void onParentsHateMe() {
// forget about that girl
}
}
Then you can do:
mGirl.flirt (myGirlFlirtListener);
And the code is indeed elegant: With one interface you control all the possible answers! It's the same for a lot of objects in java (and Android).
Instead of creating the listener as an object, and setting it, you can as well create it as an anonymous class if you won't reuse it, of course.
EDIT
How to create a generic clicklistener?
Sometimes, in the same dialog, you have 15 or 20 buttons that do more or less the same, and only differ in a detail. Although you can perfectly crete 20 clicklisteners, there's a cooler way taking advantage of View.setTag() function.
setTag allows you to store whatever object you want to any view. You use that do distinguish, inside a clicklistener, which button was pressed.
So imagine you have 5 buttons: Brian, Peter, Loise, Krasty and Sue:
mButtonPeter.setTag("Peter Griffin");
mButtonLouise.setTag("Louise Griffin");
mButtonBrian.setTag("Brian");
mButtonKrasty.setTag("Krasty");
mButtonSue.setTag("Sue");
OnClickListener personClickListener=new OnClickListener() {
#Override
public void OnClick(View buttonPressed) {
String person=(String)(buttonPressed.getTag());
// you pressed button "person"
Toast.makeText(buttonPressed.getContext(), "Hey, "+person+", how is it going!!", Toast.LENGTH_SHORT).show();
}
};
mButtonPeter.setOnClickListener(personClickListener);
mButtonLouise.setOnClickListener(personClickListener);
mButtonBrian.setOnClickListener(personClickListener);
mButtonKrasty.setOnClickListener(personClickListener);
mButtonSue.setOnClickListener(personClickListener);
Isn't it cool?

When you are "setting an onClickListener" what you are doing is telling: "when this button is clicked, execute this code".
The code to be executed is implemented in the provided annonymous function.
You can't simply do btn.setOnClickListener() without an argument because that would not provide the information regarding which behaviour to perform when the button is clicked.

Related

how can i cycle trough a bunch of buttons to reduce the code?

hiI have this code where i need to tho the same operation on different object of the same type,like initialize a bunch of buttons and setting every time the value of the text, now my code looks like this:
public void inizializzazioneGrafica(){
txtprimaCarta = (TextView)findViewById(R.id.txt_primaCarta);
punteggioG1 = (TextView)findViewById(R.id.punteggioG1);
punteggioG2 = (TextView)findViewById(R.id.punteggioG2);
btn_g1_1 =(Button)findViewById(R.id.btn_g1_1);
btn_g1_2 =(Button)findViewById(R.id.btn_g1_2);
btn_g1_3 =(Button)findViewById(R.id.btn_g1_3);
btn_g2_1 =(Button)findViewById(R.id.btn_g2_1);
btn_g2_2 =(Button)findViewById(R.id.btn_g2_2);
btn_g2_3 =(Button)findViewById(R.id.btn_g2_3);
}
public void aggiornaGrafica(){
txtprimaCarta.setText(Integer.toString(tavolo.getBriscola().getNumero())+"\n"+tavolo.getBriscola().getSeme().toString());
punteggioG1.setText("Punteggio: "+Integer.toString(giocatore1.getPunteggio()));
punteggioG2.setText("Punteggio: "+Integer.toString(giocatore2.getPunteggio()));
btn_g1_1.setText(Integer.toString(giocatore1.carte.get(0).getNumero())+" "+giocatore1.carte.get(0).getSeme().toString());
btn_g1_2.setText(Integer.toString(giocatore1.carte.get(1).getNumero())+" "+giocatore1.carte.get(1).getSeme().toString());
btn_g1_3.setText(Integer.toString(giocatore1.carte.get(2).getNumero())+" "+giocatore1.carte.get(2).getSeme().toString());
btn_g2_1.setText(Integer.toString(giocatore2.carte.get(0).getNumero())+" "+giocatore2.carte.get(0).getSeme().toString());
btn_g2_2.setText(Integer.toString(giocatore2.carte.get(1).getNumero())+" "+giocatore2.carte.get(1).getSeme().toString());
btn_g2_3.setText(Integer.toString(giocatore2.carte.get(2).getNumero())+" "+giocatore2.carte.get(2).getSeme().toString());
btn_g1_1.setBottom(Color.LTGRAY);
btn_g1_2.setBottom(Color.LTGRAY);
btn_g1_3.setBottom(Color.LTGRAY);
btn_g2_1.setBottom(Color.LTGRAY);
btn_g2_2.setBottom(Color.LTGRAY);
btn_g2_3.setBottom(Color.LTGRAY);
}
what can i do to reduce the lines of code?
I thought maybe using a for cycle but i dont know how to call the different buttons every time since they have an unique name, can someone help me with this?
To reduce code used for binding view (in your inizializzazioneGrafica method) , you can use ButterKnife library. Your code will be something like this :
public class YourActivity extends Activity {
#BindView(R.id.txt_primaCarta) TextView txtprimaCarta;
#BindView(R.id.punteggioG1) TextView punteggioG1;
#BindView(R.id.btn_g1_1) Button btn_g1_1;
#BindView(R.id.btn_g1_2) Button btn_g1_2;
#BindView(R.id.btn_g1_3) Button btn_g1_3;
#BindView(R.id.btn_g2_1) Button btn_g2_1;
#BindView(R.id.btn_g2_2) Button btn_g2_2;
#BindView(R.id.btn_g2_3) Button btn_g2_3;
...
public void aggiornaGrafica(){
...
}
}
To simplify your aggiornaGrafica you can use 2-dimensional Array or List (like ArrayList) but it won't give you anything but complexity in your code. Strive for effectiveness not efficiency.

Why do we implement View.OnClickListener if we can have to set android:onClick either way?

Edit: No, this is not a duplicate for the given link is asking for the comparison of setOnClickListener and android:onClick. I'm not even asking for a comparison, but I'm asking about the advantage of having an implementation of View.OnClickListener.
Please be free to vote to re-open.
Many people, by preference, use
public class TrumpLocator extends Clinton implements View.onClickListener{
#Override
public void onClick(View v){
//...
}
}
However, if I'm not mistaken, either way, on your Button you have to do:
android:onClick="onClick"
But, again if I'm not mistaken, if we don't override onClick and implement View.onClickListener, we will achieve the same effect:
//no override and no "implements onClickListener"
public void onClick(View v){
//...
}
and
android:onClick="onClick"
So, is there any advantage of implementing the method over simply applying the click listener? Isn't it just a waste of code?
either way, on your Button you have to do:
android:onClick="onClick"
No, this isn't required.
I think you have it backwards maybe. By having android:onClick="onClick", you need a public void method with that name in the quotes.
public void onClick(View v){
//...
}
This is similar to implementing the interface, but not the exact same. In other words, it could just as well be android:onClick="handleClick", then you need
public void handleClick(View v){
//...
}
People may not prefer this because it can lead to typos and uncertainty where a click listener is attached.
Now, the Activity does not need to implement the interface itself, you can attach anonymous class listeners to the views individually.

Managing activity from DialogFragment

How can I call finish() and other non static methods from a DialogFragment in the activity that created it? I have tried passing messages from the OnClickLisener in the DialogFragment, to no avail.
I have a really simple app, conssting of a MainActivity and DialogFragment:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity);
showDialog();
}
public void showDialog() {
DialogFragment newFragment = new ConfirmDialog();
newFragment.show(getFragmentManager(), "dialog");
}
}
And the Dialog is again very simple:
public class ConfirmDialog extends DialogFragment {
#Override
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Confirm you want to continue?")
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//finish() MainActvity
}
})
.setNegativeButton("No.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Do nothing in MainActity
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
There are many options. One of them is define an interface with a single method inside.
Have the dialog caller implement that interface.
Keep a global variable pointing to the caller.
Set the variable in the onAttach(Activity activity) method.
Null that variable in the onDetach() method.
Call the variable (interface member) method in the onClick.
Example:
public class MainActivity extends Activity implements MyInterface {
// ...
#Override
public void onChoose() { finish(); }
}
And inside ConfirmDialog:
public static interface MyInterface {
public void onChoose();
}
private MyInterface mListener;
#Override
public void onAttach(Activity activity) {
mListener = (MyInterface) activity;
super.onAttach(activity);
}
#Override
public void onDetach() {
mListener = null;
super.onDetach();
}
And then call mListener.onChoose() anywhere inside your class.
I know this has been marked as accepted, but I figured I could provide more feedback to the discussion.
A note about using or not interfaces. Andy's answer works just as right as mine, hence why I said "There are many options. One of them is...".
However, the reason why I prefer interfaces for this particular problem is because most of the times you're going to extend and reuse simple/common confirmation dialogs like that. hey are too generic to be "wasted" (or worse: duplicated if different event actions arise).
Unless you are deadly sure that you are going to use that only once, for one purpose (finishing), you generally should avoid hardwiring (and simplifying) the implementation details of the Activity in your dialog class. Flexibility, abstraction and efficiency. Less code to maintain.
And yes, there is a telltale that you may need that: the public keyword that you're using, especially if it's in a self-contained class file, which begs for reuse (too). Otherwise, you should be hiding that class inside your main Activity, since the implementation details (would) relate only to that one. Also, you would be removing the public keyword.
Yes, you could use for more than one Activity, but you'd be limited to finish()ing. The interface will give you flexibility to do whatever you want in each Activity. In other words, it's up to the implementer to define how it should itself behave for that event. You self-contain implementation details.
As a sidenote, what I do is create a package with all dialogs I may need for my application. For confirmation dialogs like that, I reuse for different messages and buttons. I provide defaults, but also allow for change using setArguments. And I keep the interfaces related so I don't need to create one interface for each dialog. The implementer responds according to which dialog triggered the "dialogs callback". Flexibility, abstraction and efficiency, all while avoiding things humorously called Hydra and Royal Family. So. In the end, like I said, many options. Don't over-engineer, but don't simplify too much too early (leave room for graceful expansion).
It's more important to understand advantages and pitfalls than choosing this or the other answer.
Even though the amount of work involved to make the interface is small, I don't see why you need to call finish() from the Activity that created it. Calling finish() from within the DialogFragment itself will suffice. If you need to send info back with it as well for some reason, you could always call getActivity() and chain a method that exists in the Activity. Ultimately no matter where you call finish, it will detach the Fragment and destroy it.
Just to clarify how to call a method from your Activity in your Fragment
((YourActivity)getActivity()).someMethod(param);
You MUST caste it because Java doesn't know that Activity has whatever method you wanna call. Which ever way you decide to go with, good luck :)
cheers
EDIT
I appreciate your clarification David. In general you are correct. But to be honest in this instance, you are incorrect because of the nature of Fragments and their relationships with the Activity. Again, you will essentially be creating a listener in order to be called by a Fragment that already has an extremely close relationship with the Activity class it is being held by. Any benefits provided by not hardwiring anything through listeners is lost in this case. You will still be rewriting custom code for every Dialog. While in my method you can write a method in the Activity class in such a general way that you only ever have to write it once.
There are only two reasons I see a need to use a Listener:
1. If you are writing code that other people will be using. So you provide an easy way to give info while maintaining a certain structure (like Androids DatePickerDialog).
2. If there is no connection between two parts you are trying to maintain connected (like GUI's in Java).
So I am not trying to say that David is wrong in saying this, and I am grateful he is bringing it up because it is important for people to understand when to use them. But again, in this case the benefits he mentions are non-existent due to the connection between Fragments and the Activity class. Just wanted to clarify why I believe listeners are not necessary here.
Instead of:
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//finish() MainActvity
}
})
Use:
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// this gets the current activity.
Activity currentActivity = getActivity();
// this finish() method ends the current activity.
currentActivity.finish();
}
})

A difference in to ways of handling clicks

I'm a total beginner in coding for Android and java in general and so far in various tutorials I found two ways of handling buttons being clicked.
The first one:
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//do your thing
}
});
The second one involves putting android:onClick="someMethod" in a button's properties in the main.xml and then simply creating the method someMethod in the activity.
I was wondering what is the difference in those two approaches. Is one better than another? Or do they work only subtly differently? To me they seem to do the same :P
Thank!
I was wondering what is the difference in those two approaches. Is one
better than another?
The result is same. But difference is in readability of code.
android:onClick="someMethod"
this approach i don't recommend to you.
I recommend to you use anonymous classes like you meant above.
Also your class can implement for example View.OnClickListener and then you only have to implement onClick() method and you can have one method for many widgets.
public class Main extends Activity implements View.OnClickListener {
public void onClick(View view) {
switch(view.getId()) {
case R.id.startBtn:
// do some work
break;
case R.id.anotherWidgetId:
// do some work
break;
}
}
}
I think this is also good practice, you have only one method and code have less lines and is cleaner.
In first one: You are defining a method pragmatically, that will be called at every press of the button.
In Second one: you are mentioning method name of the activity that will called when button will be pressed.
It totally depends upon your preference which way you like to set a click listener.
Personally, I like to set click listener pragmatically, so that I know which code will execute at onClick of a Button, while going through code.
When you use android:onClick="someMethod", the method is on the activity that holds the clicked view. If you're using this on a list item, it'll be more convenient (in some cases) to have the click handled on the activity.
If you'll use the anonymous class approach, you'll need to set it on the adapter, which not always have access to the activity (and if so - it could get messy..). So if you need stuff from the activity that's holding you list (holding that clickable item) - I think it'll be cleaner to use the android:onClick approach.
Besides that - it's pretty much the same. Be sure to document the methods you call with android:onClick, since it's sometimes hard to track their source later.
To handle double click on android button
// These variables as global
private final static long DOUBLE_CLICK_INTERVAL=250;
private static boolean doubleClick=false;
private static long lastClickTime=0;
private static Handler handler;
// In button method
long clickTime=SystemClock.uptimeMillis();
if(clickTime-lastClickTime <= DOUBLE_CLICK_INTERVAL) { // If double click...
Toast.makeText(getApplicationContext(), "Double Click Event",Toast.LENGTH_SHORT).show();
doubleClick=true;
} else { // If not double click....
doubleClick=false;
handler=new Handler();
handler.postDelayed(new Runnable(){
#Override
public void run(){
if(!doubleClick){
Toast.makeText(getApplicationContext(),"Single Click Event",Toast.LENGTH_SHORT).show();
}
}
}, DOUBLE_CLICK_INTERVAL);
}
lastClickTime=clickTime;

Please explain this structure and why it's used like this?

I found the code segment below in [this tutorial][1]. I don't understand what exactly happens. It seems like the button is created and that a listener is then set to listen for when it's clicked, but why is the entire onClick(View view) method inside the (...) of the sendMail.setOnClickListener()?
Regarding setOnClickListener, Eclipse said:
Register a callback to be invoked when this view is clicked. If this view is not clickable, it becomes clickable.
So am I correct in saying that the structure is as it is to almost simultaneously see if the button is clickable, make it clickable if it isn't and create a listener for the button?
But I still don't understand why it was written and structured like this:
Button sendMail = (Button) findViewById(R.id.send_email);
sendMail.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Mail m = new Mail("email#gmail.com", "password");
m.setTo("email#gmail.com");
m.setFrom("email#gmail.com");
m.setSubject("This is an email sent using my Mail JavaMail wrapper from an Android device.");
m.setBody("Email body.");
try {
m.addAttachment("/sdcard/filelocation");
if(m.send()) {
Toast.makeText(m, "Email was sent successfully.", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Email was not sent.", Toast.LENGTH_LONG).show();
}
} catch(Exception e) {
Toast.makeText(getApplicationContext(), "There was a problem sending the email.", Toast.LENGTH_LONG).show();
Log.e("MailApp", "Could not send email", e);
}
}
});
In my mind it should be:
sendMail.setOnClickListener();
sendMail.onClick(this);
public void onClick(View view) {...}
Any comments or Register a callback to be invoked when this view is clicked. If this view is not clickable, it becomes clickable.
This is basically a subclass. This method is known as anonymous subclassing. It allows to you to create a subclass and use it together.
Anonymous subclass do not have constructors as the class has no name. For that you need to use instance initialisers. Basically these classes are used when creating another class file for it feels redundant and if you want to keep the class code together in the same block(Atleast that why i use it for).
It is called an anonymous class. Instead of creating a new class with the class keyword, you just use the syntax new <superclass-or-interface-name>() { ... } with all the required methods.
Read more about anonymous classes at Wikibooks
It's called an anonymous inner class, its a common Java pattern. You are free to define an explicit class that implements the method and set your listener to it, instead.
That's just how it works when you create a new instance of the Listener inside the setOnClickListener() method. Nothing weird about that at all.
Alternatively, you can set a method for android:onClick in the button XML side. In code, you'll need to do the following:
public void testMethod(View v) {
// code
}

Categories

Resources