A difference in to ways of handling clicks - android

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;

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.

Simpler OnClickListener?

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.

onBackPressed() with arguments

I'm using onBackPressed() method in my app in few places.
In every place I want this method to do other stuff.
When user is in X layout I want to Back button does somethink else than in Y layout, so I'm thinking that the best solution would be to use arguments in onBackPressed method.
For example in X onBackPressed(0); and in Y onBackPressed(1); etc.
#Override
public void onBackPressed(int c){
if(c==0)Toast.makeText(getApplicationContext(), "This is X", Toast.LENGTH_SHORT).show();
if (c==1)Toast.makeText(getApplicationContext(), "This is Y", Toast.LENGTH_SHORT).show();
}
But it does not work.
Do You have any ideas what can I do to make it work ? Or is there any better solution for this problem?
you are overriding a framework method and you can't pass it any other parameters than those defined by the API. However you can create an own method to check what you need like:
#Override
public void onBackPressed(){
switch(checkLayout()){
case 1: //do stuff
break;
case 2: .....
}
}
And to extend CommonsWare's comment a little: yes, users are not "in a certain layout". Users are interacting with a certain Activity that is hosting a certain layout. If you don't really understand what this means, you should probably consult this document: http://developer.android.com/reference/android/app/Activity.html
The way overriding methods in Android works is that you must exactly duplicate the method header. When you change it, it will still compile, but Java will read it as an overloaded method and thus not do anything with it because it is never called.
You would be a lot better off handling an instance variable outside of onBackPressed() and then handling it when it's actually pressed.
The following is a simple implementation.
//Your instance variable
boolean myRandomInstanceVariable = true;
#Override
public void onBackPressed()
{
if(myRandomInstanceVariable)
{
//do stuff
}
else
{
//do other stuff
}
}
Create a field in your class set it to some value in some place to some other value in some other place. Then in onBackPressed() check that field's value and proceed accordingly.

Update Android UI from a thread in another class

I've seen a few questions on here asking similar questions, but I've not yet seen a suitable answer. Many people have asked how to update the UI from a thread, but they're almost always in the same class as the UI.
What I'm trying to do is update the UI from a thread which has been created in another class. I've seen all of the suggestions, such as async, handlers, runnable, etc... but I've having real trouble implementing them in separate classes.
I'm trying to keep my UI class minimal and only deal with interactions with the GUI, such as when a user presses a button. Now, I've created a new thread, in a new class, which connects to a Bluetooth device, but I then want to change a button in the UI thread from being a 'connect' button to a 'disconnect' button (i.e. change the button from creating the Bluetooth socket to closing it).
What is the general way to do this? Am I thinking of this all wrong and should have everything in one class? What is the correct way to interact between the 'main' UI class and other classes/threads?
Ideally I want to be able to do other UI interactions, so some solution which allows other UI changes outside of the UI class would be great!
What I'm trying to do is update the UI from a thread which has been
created in another class. I've seen all of the suggestions, such as
async, handlers, runnable, etc... but I've having real trouble
implementing them in separate classes.
Generally for your goal i recommend to you use:
AsyncTask
IntentService with ResultReceiver
I don't think that its too tricky. Absolutely not. If you have it as separated class(es) and not as inner class(es) in some Activity class so i recommend to use constructor where you will pass context, widgets, generally whatever you want and then in correct methods(which allows UI update) update your UI.
I'm doing it because i like when i have clean classes(so UI class have only UI implementations and logic is positioned separately).
Example:
public class TaskExample extends AsyncTask<Void, Integer, Void> {
private Context c;
private Button b;
public TaskExample(Context c, Button b) {
this.c = c;
this.b = b;
}
protected Void doInBackground(Void... params) {
// some work
if (isSomethingConnected) {
publishProgress(Constants.IS_CONNECTED);
}
return null;
}
public void onProgressUpdate(Integer... params) {
switch (params[0]) {
case Constants.IS_CONNECTED:
b.setText("Connected");
break;
case Constants.ANOTHER_CONSTANT:
// another work
break;
}
}
}
Usage:
public class Main extends Activity implements View.OnClickListener {
private Button b;
public void onCreate(Bundle b) {
super.onCreate(b);
// initialise widgets and set listeners to appropriate widgets
}
public void onClick(View v) {
switch(v.getId()) {
case R.id.connectBtn:
startWorker();
break;
}
}
private void startWorker() {
TaskExample te = new TaskExample(this, b);
te.execute();
}
}
There are a couple of options. If you have access to the View you are changing and simply need to force a refresh, you can use View.postInvalidate() from any thread. If you need more complex operations, such as changing the text of a button, you should use runOnUIThread, which requires access to the Activity context. This should be simple to get - just add it as a parameter for your custom Object's constructor. With this context, you can do something like this:
activityContext.runOnUiThread(new Runnable(){
#Override
public void run() {
myButton.setText("disconnect");
}
});
Use the runOnUiThread(Runnable) method to run something on the Main thread and call the ClassName.View.invalidate() method if it is a view or just make a public method in you're Target class which handles the refreshing of the UI.

Categories

Resources