In Android there seems to be 3 common ways of handling button clicks, how much difference is there between the methods? And are any of them 'better' in some way?
The three methods I keep seeing are:
Anonymous class
Find the button by it's ID, then pass a new anonymous class to setOnClickListener, e.g. in onCreate
findViewById(R.id.myButton).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// .. Whatever
}
});
Implement OnClickListener
Implement OnClickListener and pass this to setOnClickListener, then use a switch statment based on the button ID, e.g. in onCreate
findViewById(R.id.myButton).setOnClickListener(this);
and implement onClick like
public void onClick(View v) {
switch(v.getId()) {
case R.id.myButton:
// ... whatever ...
break;
}
}
Use onClick XML atribute
In the XML layout for your activity, instead of giving your button an ID, use onClick like this:
<Button
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:onClick="buttonClicked"
android:text="Button" />
Then have a buttonClicked method in your Acitiviy like this:
public void buttonClicked(View v) {
// ... whatever ...
}
At the moment I tend to use the XML attribute, but that's just because it involves the least amount of code. When should I use the other methods?
The first two are the classic approaches. Which one you prefer is more of a general Java question than an Android question.
The third one was added later to make things easier.
Setting up a click listener on a button is very common task, but it
requires quite a bit of boilerplate code. One way to reduce the amount
of boilerplate is to share a single click listener between several
buttons. While this technique reduces the number of classes, it still
requires a fair amount of code and it still requires giving each
button an id in your XML layout file. With Android 1.6, none of this
is necessary. All you have to do is declare a public method in your
Activity to handle the click (the method must have one View argument)
Source
I've really always seen it as preference. I'm not sure there's any performance advantage to either other than the last two methods may be slightly faster since they're not creating objects at runtime.
The first option isolates the code to the single button so it's very easy to debug since you know only that code will be executed when that button is clicked. However, many buttons can cause initialization methods to expand to large sizes.
The last two methods put all button handling in one place which can be convenient and cleaner at times, but with many buttons you have to decipher which button was tapped by the user via the v.getId() method.
The last option allows you to easily specify specific methods for specific buttons so you can separate them out like that, but again you'll have many methods used for single purposes.
I've always used the inline method (anonymous class) for custom dialog windows that have buttons since it keeps the code with the rest of the dialog rather than in an activity or class. I just initialize the buttons of the custom dialog when I override the onCreateDialog.
I implement the OnClickListener on the Activity if the buttons are on the main window.
Related
I have a question about handling click event of button.
I have already read this article
I know the difference by code, styling, readable... But I do not know the difference about performance in these two ways:
The first way:
buttonA.setOnClickListener(this).
The second way:
buttonB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// To do something
}
});
Has anyone found out this?
If there is one you shouldn't worry about it because it's that small.
Readability is much more important.
'The second' way creates one more object.
In second way you are creating new View.OnClickListener, Objects take time to create, and memory to keep them available.
I'm avoiding implementing listener in my classes, i prefer to use annonymous class (Second way), if I have to use listener in many places than I am creating field that holds it.
The first method implements the OnCLickListener class whereas the second method creates an Anonymous class.
The first method will result in your code being more organised and neat, but if you have multiple buttons, then you have to add more code to the OnCLick method.
Whereas in Anonymous classes, every time a click event occurs, a new object is created, which really doesn't affect the performance. The effect is negligible. But since the objects are dynamically created, which means the Garbage Collector should free the associated memory once the object is no longer being used.
TO summarise, there is almost negligible difference in both their performances. Deciding which one to use mostly depends on your need/requirement.
I have 3 activities with the same toolbar. I would like to avoid copying code on each activity. I know I can use <include> tags in every layout in order to reuse the same layout for the toolbar. Now I would like to share the event handlers for each button of the toolbar in all the activities. I am thinking of making a toolbarActivity which extends Activity class and the 3 activities extends toolbarActivity, so in onCreate method, when I call base.OnCreate, all the event handlers would be defined. But, SetContentLayout was not called yet, so base.OnCreate will not find the buttons. Remember the 3 activities have different layouts. Do you know the best way to reuse code in order to avoid copying all the event handlers in OnCreate method for every activity and allowing me to override some functionality?
Android is used on mobile devices so at development time their is no way to know the size and dimensions of the users device. On large devices many UI elements can fit. On smaller devices few UI elements can fit. Your question relates to this dilemma and therefore has many possible answers. Logically for code to work it must exist inside the source, ie you could cut and paste, a bad solution because you end up with many versions of this "same" toolbar or you could refer/reference one "external" toolbar. Fragments come to mind as does having a separate source file. UI source files can be thought of as pairs. Java for dynamic elements and xml for static. So in summary just reference an external fragment that has implemented your toolbar.
If you keep the naming conventions for the buttons and other things in each layout that are tied to the references in your activities then you should have no problem.
For example if you have a '#+id/login_button' in one layout then just use the same convention for the same type of button in the next one and youll be fine.
You could define a base activity which all your other activities extend, and make it implement a click listener (or whatever interface you are using to listen for button presses). You can check the Id of the clicked view and thus provide a callback to perform whatever logic you want.
public class BaseActivity extends Activity implements OnClickListener {
public void onCreate() {
myBtn.setOnClickListener(this);
}
public void onClick(View v) {
if (R.id.my_btn == v.getId()) {
onFoo();
}
}
protected void onFoo() {
// TODO handle foo
}
}
You can then override the method in your subclasses if you need to provide different behaviour.
public class DifferentActivity extends BaseActivity {
#Override protected void onFoo() {
super.onFoo()
// TODO handle foo differently
}
}
I am trying to create a library, lets call it L. A company has an android app, say A.
L can be linked to A such that in the codes of A, the dev just needs to add something like:
L l = new L("client_id")
l.startTrack();
Now L should be able to track all clicks that happens in A and pass to a server for logging. AppSee is a product that is already doing this.
I am wondering how can i intercept every user action to get the action target name (button title? textfield?)
Thank you!
What you are asking is EventTracking, like in GoogleAnalytics. But the approach you are doing is different. In Google analytic one needs to start event to event tracker. Like say you have a 3 buttons and you need to track each button separately, there you put 3 separate events trackers.
If you want to track all the events going through the activity you need to implement Activity's onInterceptTouchEvent(). Whenever a touch event happens in an activity, it passes through the said method above.
As Google says
Implement this method to intercept all touch screen motion events.
This allows you to watch events as they are dispatched to your
children, and take ownership of the current gesture at any point.
with caution
Using this function takes some care, as it has a fairly complicated
interaction with View.onTouchEvent(MotionEvent), and using it requires
implementing that method as well as this one in the correct way.
For more Event details, look here.
OnClickListener is a Interface. so you can implementing it's in any class
It's pretty easy. Since every control on the screen is a subclass of view, you can do something like this:
public static void logClicksOnMe(View v){
v.setOnClickListener(new View.OnClickListener{
#Override
public void onClick(View v){
//TODO Log code
}
});
}
Obviously that would destroy the listeners you already set on such object, but you can do something like this:
public static void setLoggedListener(View v, View.OnClickListener listener){
v.setOnClickListener(new View.OnClickListener{
#Override
public void onClick(View v){
//TODO Log code
if(listener!=null) listener.onClick(v);
}
});
}
The developer will have to set the listeners manually, but he already has to, so neither the workload or the code should change much. The advantage over the onInterceptTouchEvent() activity interface is that you can absolutely control which view are gonna be tracked and the developer is not constrained to use your abstract activity (let's say he already is using other abstract activities from third parties, like SlidingActivity or things like that.), so the maintenance and implementations efforts are pretty small.
Not exactly, actually there is something more easier, you can ask them to inherit there activities from your activity
eg. A extends L;
Do this in following steps.
1. Create the library(say L is com.click.counter), with event handles counter like explained in many reply above, using view.onclicklistner. In onclick event, The only difference is use package name. As context is of the app which is calling the library, you can use
Context::getPackageName
http://developer.android.com/reference/android/content/Context.html#getPackageName%28%29
2. onclick events, you may log and sync in one go, at end of day/scheduled time, or on every click. you may use httphandler for that
See
https://cloud.google.com/appengine/docs/go/gettingstarted/helloworld?hl=en
2. Create a test apk(A),add the library as dependency in gradle.
dependencies {
compile 'com.click.counter'
}
3. Inherit all the activity in test apk from class A
right i have a sign in button located exactly in the same place on every activity and i have bout 20 activities at the moment but will rise a lot higher soon, and i don't really want to be copying and pasting the same code in to each activity, so I'm looking for a simple, efficient solution to handle the onClick event which will work globally throughout the app.
For example, if User A clicks on the sign in button on Activity 1 and signs in, it will show that he is signed in on Activity 2 and 3 and so on.. until they log out.
The sign in button has the same ID throughout the whole application which is "#+id/signIn"
Would it be easier to call a single function at the beginning of each activity? I thought that wouldn't be every effective use of processing power etc?!
Any suggestions and/or guidance would be much appreciated. Thank you :)
You can't avoid implementing that listener in all of your activities in either ways. But you can do it in a bit more organized way:
You could write a custom header layout for your application (/res/layout/header.xml), in which you have the "Sign In" button with a click listener set (pointing to an onSignInClicked method):
android:onClick="onSignInClicked"
Then you include this header to each activity layout:
<include android:id="#+id/header" layout="#layout/header" />
You could also create an interface which contains an onSignInClicked method declaration, and by all your activities implementing that interface you force them to define the onSignInClicked method's body.
What you actually do there can also be wrapped into
a static method inside a globally
accessible class, or
a well-parametrized method inside
your Application extension class.
so in all of your activities this method can be:
public static void onSignInClicked(View view)
{
// static method with call with reference to the current activity
SignInHelper.doSignIn(this);
}
or
public static void onSignInClicked(View view)
{
// global method in your `Application` extension
// with reference to the current activity
((MyApplication)getApplicationContext()).doSignIn(this);
}
If you choose the second way, don't forget to update your androidManifes.xml by setting the name attribute of your application tag:
<application android:name=".MyApplication" [...]
You could create the button as a custom view.
I'm new to Android, and event driven code in general. Rather than embed loads of anonymous event listener classes in my Activity to handle onClick events etc, I defined separate classes to keep the code clean. Then I use them e.g. like this
myButton.setOnClickListener(new MyEventListener());
So, when 'myButton' gets clicked, MyEventListener's onClick method does some stuff.
I wanted to know the best practice for
a) accessing things in my Activity from the event listener. For example to change the text of a label. The onClick event takes a View in, but this is the view for the button that's been clicked, so if the label is NOT a child of my button, I can't use findViewById to get a handle to it. I've modified the constructor to pass in a reference to the label, so that the event has a handle to it but not sure if this is the most elegant way of doing it.
b) Passing information back e.g. when my event fires, I might want to disable some EditText fields. I'm thinking the proper way to do this is probably to dispatch another event from my event listener, that the Activity listens for, and when it sees the event, disables the fields in question. Is that the way to do it in Android?
Hope someone can help, really appreciate it.
Thanks
An alternative to using explicit event listeners, anonymous or not, is to use the onClick attribute in xml to directly dispatch to a method as in the following example:
Layout xml file:
<Button android:onClick="buttonClickedCallback" />
Now simple define a method on your activity:
class CustomActivity extends Activity {
public void buttonClickedCallback(View clickedButton) {
// do stuff
}
}
This is available since Android 1.6 as described in UI framework changes in Android 1.6.