This is a double question about using interfaces - namely onclickListener (and related) within an Activity.
onCreate should be short - so says the documentation - but if I have lots and lots of views all of which have onClickListeners it can get quite long. I'm worried this will cause the UI thread to timeout. Is this a problem?
Is there a best way to use onClickListener? By which I mean, is it better for the Activity to implement onCLickListener and then have a very long onClick() method? Or do the following:
mView.setOnClickListener(new OnClickListener(){
...
});
for each View? Does it really make any difference?
They mean "short" in that don't do anything that takes a long time to process in onCreate(). Anything like math computations, networks or database access, extremely large bitmaps inflations should be done in a thread. The only overhead that setting an onClickListener to a view is calling a method, setting a reference, and usually creating an object. If object creation does any of the aforementioned things, then it would be best to pre-load the object before creating it.
There's no real difference. What you choose depends entirely on your implentation and coding stye. Using an anonymous object like you showed is kind of like a "set-and-forget" style way of doing it. It's suitable if the action is unique to the button. Creating a whole new class that that implements onClickListener() would be required if there needs to be a state that persists with each click. That way, you create the object once and set all the necessary views to the single object. It may also be useful to do it in that fashion if many views do the same action when clicked.
It shouldn't bother with the loading of your activity because the code inside onClick listener is executed only when a click is made on its view.
Besides, its not a good idea to execute heavy stuff (network, database, drawable manipulation, etc.) in onCreate. In case if you really need to do such processing then off-load it to an AsyncTask which runs your code in a separate thread causing your UI (main) thread to be free.
1) I agree with Deev's answer.
2) Please note that if you choose to use the anonymous inner class solution
mView.setOnClickListener(new OnClickListener(){
...
});
You create an object for each assignment.
Conversely if you implement OnClickListener in your activity you won't create any other object. This doesn't make so much difference for a small number of object but could save some memory (and save you from GC) for larger number (and you said to have a lots and lots) of objects. Avoid unuseless object creation is suggested in Designing for Performance
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've got an activity with several instances of a custom View. This custom View is passed an object, and the contents of this object will decide how the View is displayed.
Also, when the View is created, an OnClickListener is added to it. The previously mentioned object is passed on to this onClickListener through a contructor and private variables, and inside the listener I've got a switch statement which will handle the OnClick differently depending on the object-data.
Is there anything fundamentally wrong with my approach? Would it be better to have several OnClickListeners, and add the correct one from the View, instead of evaluating the object inside the OnClickListener, thus reducing the size/memory footprint? I'm guessing all the onClickListeners will be loaded as objects in memory once the activity loads?
Maybe I should access the object and context through the view that is passed to onClick instead of passing them as arguments (and duplicating them?), however I'm struggling with acheiving this...
I'm basically looking to optimize CPU and memory usage. The program runs fine as is.
You may check this out:
How to test the performance of an Android application?
For memory:
Try to avoid (lots of) "new ..." calls. The more u create the more the GarbageCollector has to clean up afterwards. This create/cleanup needs a lot of performance.
I am a .NET mobile developer and since i started working with android, i noticed that the only way i can store my event handlers of the views is through the activity file or by creating a class to hold all these event listeners. Can someone suggest best way that i can do to have the least clutter and store all the event handlers accordingly?
A bit subjective as "clutter" depends on how efficient you are at implementing your event handlers and how complex your app is.
For instance I've seen example code here on SO like...
button1.setOnClickListener(new View.OnClickListener {...});
button2.setOnClickListener(new View.OnClickListener {...});
button3.setOnClickListener(new View.OnClickListener {...});
In each case an anonymous listener for each individual Button often performing a very similar function (start activity 1, start activity 2....). The cleanest way would be to implement View.OnClickListener on the Activity itself and then use...
button1.setOnClickListener(this);
...(and so on for each Button) then get the resource id of the View passed in to the listener to identify what was clicked and what needs to be done. It amazes me how many people don't get that.
As for creating a separate class (or classes) to hold listeners, that gets tricky depending on how many activities you have going on. Maintaining the listeners separately has two downsides.
Firstly if you don't go with the model of having an Activity use anonymous listeners or implement the listener directly, that suggests you'll have a whole load of activities (which may be extended at some point) using your 'helper' class listeners. Each time you extend your Activity you need to make sure the separate class is updated to cope with it - potentially an out of sight, out of mind problem where you want something new from an Activity which your 'generic' listener doesn't handle.
The second potential problem is in the way Android works (depending on your app). An Android Activity is meant to be modular - if it displays photos or images or documents of a particular format then it should be as self-contained as possible. Having a separate class with a multitude of listeners in means that a very simple Activity meant to do a very simple task ends up loading a bloat of a class (or classes) which contains a whole load of listeners which aren't relevant.
Stick with simple - optimise the listeners for each Activity and keep them self-contained. If you feel there's any duplication going on, define your own base classes and extend from there.
It's not clear what result you want to get. As I understand, you do not want to create any Activity subclass to handle the UI events. If so, then it is really weird - how would you show those views not within an Activity?
1) I don't underestand why the samples of Android almost use AsyncTasks as private inner classes. I know it is convenient to make it inner class but it makes our class file longer and hard to read. ShelvesActivity of Shelves sample application have even 845 lines. Don't you think it is a bad design or bad construction?
2) If I make my ScanStorageTask external class, what do I have to pass to it? entire Activity or only used widgets?
Example: If I must use a WebView, a Button and a ProgressBar in ScanStorageTask.
I use this:
ScanStorageTask task = new ScanStorageTask(this); // "this" is activity reference, then get the webView, button, progressBar from it.
or this:
ScanStorageTask task = new ScanStorageTask(webView, button, progressBar);
There's nothing wrong with doing it externally, and it actually might be a better design. Passing UI elements around is the kind of tight coupling that can get you into trouble when you have a really large code base anyway.
Why not do it externally and use the "listener" pattern that the UI controls employ? Make your ScanStorageTask its own class, create an OnCompleteListener interface with an onComplete method, and pass that to your ScanStorageTask instance (expose a setOnCompleteListener method or something to that effect). Then, onPostExecute can just do this:
if(onCompleteListener != null)
onCompleteListener.onComplete(data);
That way, you define your UI updates inside your activity based on the data. It's better separation of concerns and will keep your lines of code per class down, as that seems to be what you'd prefer. If you don't already have this, make a class that represents the data you need to pass in and get out, and that's what you pass in to the task as a param to the execute method and what onPostExecute passes to onComplete.
Inner classes allow you to manipulate the UI of an outer Activity inside onPreExecute(), onPostExecute() and onProgressUpdate() without passing the whole UI structure(s) to the AsyncTask. You are just able to use the activites functions for that.
This is useful since manipulating the UI isn't the main purpose of an AsyncTask. It's doing non-UI background work. And for that, what you usually have to pass is some arguments to do this job (e.g. supplying a URL to download a file).
When you declare your AsyncTask external, you basically can't access your UIs resources inside onPreExecute() (no arguments are passed to this at all), and very hard inside the other two UI functions.
I'd say AsyncTask is just made for beeing used as an inner class to do work and update the UI-thread. See the description:
AsyncTask enables proper and easy use of the UI thread. This class
allows to perform background operations and publish results on the UI
thread without having to manipulate threads and/or handlers.
(from the class documentation)
I had the same problem in may application. I wanted to establish a communitation with a PC using a Socket and I wanted my code to be reusable from several Activities/Fragments.
In the first place I tried not to use an inner class but it is very convenient when you have to update the UI so I found an alternative solution :
I created an outer AsyncTask class wich in charge to communicate with the pc and I created inner classes in each of my activites/fragments with only an override of the onPostExecute() method. this way I can reuse my code AND update the UI.
If you just want to get the result of the task and if responsiveness is not essential for your application, you can use the get() method of the AsyncTask class.
Personally I belive that if you use class only at one point, then it's most readable to also define it there - hence the anon inner class.
It does not matter. From design perspective I'd only pass data that is actually needed. However you need to be aware on one possible pitfall - when activity instance gets deactivated (hidden or orientation changed) and your background thread still runs and tries to show some changes, then you can get various errors or nothing s shown at all.
I have put the all the binding code for UI events on OnCreate(). It has made my OnCreate() huge.
Is there pattern around implementing UI events in android ? Can I add methods in View xml file and then I can put all the handler code somewhere else.
In a nutshell , I think I am asking how can I implement MVVM pattern with android app code ?
Stuff that I do:
Keep all onClick functions in the XML. Avoids a lot of clutter in the Java code.
Initialize event listeners as members of the activity class rather than keeping them in a function. I don't like too many curly braces in my code. Confuses the hell out of me.
If my list adapters get too big I keep them in a separate class rather than as a member of the activity class and then keep all view listeners there in the adapter.
To avoid creating too many onClick functions I sometimes keep one function like onNavigatonClick and then use view.getId() to see which button was clicked. As the XML is not checked for valid function calls, it leads to runtime errors if your function name is wrong.
If a particular view needs a lot of UI interaction code, I create a custom view with a GestureDetector to handle UI interactions.
I guess this is still quite basic as I haven't had much experience with Java yet.
In 1.6 and later you can specify onClick methods in your layout XML file to trim a bit of the fat. I generally just hide it all away in a initUi() method that I have my onCreate method call. This way at least the onCreate is easier to read.
Lots of good answers to this already. :)
If you're using Android 1.6 or later you might find the new fragments API helpful for organizing and partitioning your activities into several logical units.
onCreate is usually the best place for calling setContentView and setting up listeners, but the code for handling the user interractions normally goes in onClick, onTouch, onKey etc. routines.
Maybe if you posted your code we could see what you've done?