So after a while of programming android apps(1 uploaded on market, have 3k+ active installs with a 4,7 rating), I started to wonder, how can I make my app even more awesome. I realized, that I couldnt really add any really new, and world changing features, so I started to inspect the performance, and how to optimize just about everything, how to find the best cpu/memory usage ratio, and so on.
Anyway, I found out that onCreate will run in the case of rotating the screen, which is quite logic, but there are some(big) calculations, that I surely dont need to redo after every rotate. One of this is iterating through a csv with 6500 rows, having 4 columns, 2 of it always contains some data, 2 of it not always. The 2 column with datas will be used for autocomplete adapter, the another 2 is optional for a feature, but it still need to be initialized. Currently, this is running in an asynctask, triggered at the end of the onCreate, and takes about 3 seconds on my HTC Desire S, which has a quite good CPU, so lower budget devices will have a longer initialize time after every rotate which is surely not I want... It wont crash the UI, but there won't be any autocomplete until thoose seconds are over.
SO: my question is, can I do this in some separate method, for example a constructor(like in standard java), or is it a bad practise, because the special lifecycle of activities? I mean, I instantiate my activity the way the "constructor" will run, and just after that, my onCreate will run. In case of rotating, my "constructor" won't run again, but the onCreate will. Stability will still be my nr1 goal. Or, is there any good way to do this? Something that is created for exactly like this, which im unaware of? I really want to improve a lot in this matter, and I would really appreciate some help in this, preferrably from ones with experience in this, but any help is welcome! :)
For example, if I want to make a new activity this way, I would do it something like this:
new MyActivity(some parameters);
so the constructor runs, which ends something like this:
startActivity(new Intent(context, MyActivity.class));
So this way, the constructor runs, my variables will be initalized(not connecting to any view etc), and after that, my activity can run its onCreate variable anytime it has to.
Pardon me if Im wrong the syntax, I just fasttyped it :)
You should decouple this logic from your activity. There are many ways to do this, but the end goal is to have your csv parsing done in a different class, and this class should expose information about whether or not the data has already been parsed. So, in onCreate, you call your class to get the data. If it already exists, you get your cached data immediately. If this is the first time the method is called or for some reason your cache has been cleaned up, you parse your csv file and do whatever calculations you need.
you could take a look at onRetainNonConfigurationInstance which can return an object which you can access after your activity has been recreated.. so you would simply return an object containing all your processed results of onCreate and the next time around you check if there is a getLastNonConfigurationInstance() - and don't recalculate everything
Related
I have heard things about how it is bad to use setContentView()
Pattern "One activity, multiple views": Advantages and disadvantages
However I was wondering, would it be unlikely that my application will cause memory leaks, if I use setContentView() once in the onResume() method of my activity?
Whenever the user opens my app, it checks to see if something has been enabled in settings. If it has been enabled then the app uses a different screen compared to the original screen.
Therefor my code looks like this:
#Override
protected void onResume() {
super.onResume();
InputMethodManager im = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
String list = im.getEnabledInputMethodList().toString();
if(Stuff is true){
setContentView(R.layout.activityscreen_enabled);
}
}
}
Would using setContentView() be unlikely to cause memory leaks and other such problems? Or is there a better solution?
I'm doing Android since few years now and I have never done that because I like to stick to the pattern which is almost always having the setContentView in the onCreate.
However, I do not believe that you would have big troubles doing that (for the memory leaks I mean).
Nevertheless, I do not see the point of doing such a thing, the pattern of the Activity (or how I understood it) is more:
I create a view in the onCreate and I update its data in the onResume and if the data are A then add/remove this view and if the data are B add/remove this other view.
To be complete, I read your (really good) link and I think you maybe misunderstood how you can apply what Commonsware is saying: you can have multiply views without having different setContentView: your view structure needs, in this case, to be really modular and you will be able to load all the subviews dynamically (or, at least, it's how my colleague and I are doing ;) ).
For your example, I would have an empty layout for the base of the activity (let's say a blue background) and then for every view I want to have (every case), I would have a dynamic layout that I load at some point in the life cycle (probably at onResume). I do not believe that what you're doing is particularly bad but I doubt that it was thought like this ^^
This link agrees with me
If you need multiple screens use a Fragment or even create a new Activity inside of messing around with the view for some reasons
It's not good to have single Activity for the whole app or it will be so long and complicated.
Your onResume() would need to handle the new views and their ids, onClickListeners... etc.
onResume() is called many times unlike onCreate() so it would be a waste of time and memory to load the views over and over.
According to android doc in activity life cycle about onPause() and onResume()
Because this state can transition often, the code in these two methods should be fairly lightweight in order to avoid slow transitions that make the user wait.
A strange behavior I'm tearing my eyes on since early this afternoon, I'm givin up understanding but perhaps someone has an idea (yeah, I'm a beginner, some PROBABLY has an idea ^^).
Situation :
MainActivity.java (first one to be called, only one of interest here)
public ExpandableListView listClubs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listClubs = (ExpandableListView) findViewById(R.id.expLstMainClubs);
AppGlobal.CreateDistricts() ;
ELVAdapterDistrictsClubs adapter = new ELVAdapterDistrictsClubs(this);
listClubs.setAdapter(adapter);
}
it's the only code in the class. Basically, I'm filling an ExpandableList with an adapter that relies on what's created in the CreateDistricts() method (creates business objects, Districts containing Clubs containing Members, Events, etc.).
Basically (again ^^), everything runs fine, on first start the ExpList works as expected, as well as the rest of the app. If I hit the back button from the MainActivity, however, and rerun the app, a "strange" (to me at least) behavior occurs :
The ExpList is loaded twice in a row - first one with the data, works fine, and just below a duplicate (with the same 2 Groups, i.e. here the only two Districts in my sample data), which doesn't work at all (if you try to expand it, it crashes the app).
Frankly, I'm lost - I've tried some things on the various on[Pause/Stop/Destroy/Start/Resume] etc. to no avail (therefore, there is yet nothing done on this side, no override, as it seems not to bring anything good).
As the onCreate will after the onDestroy load the bundle, it should load the ExpList as it were, and in this case there might be a conflict between the "old" groups/children and the actual ones (currently, data is simulated, but will afterward come from a remote data source), and I haven't decided yet what the best "save" behavior is, i.e. if I should find a way to obliterate the ExpList onDestroy in order to be sure it's 100% recreated anew (and how does one do that ?) and start from scratch, or if I could use the ExpList as is, while updating it's content, in order not to lose the previous selection. It may be irrelevant to complicate matters in order to do that, the first list being not so big and quite quickly used to reach the second activity...
Anyway, I suspect it comes from around that part, the bundle load after destroy and rerunning, does it reload the ExpList as is and then I add things instead of first deleting ? What I found confusing is that the next activity (reached simply by clicking one of the items of the ExpList) displays a similar ExpList (filled with Months and Events per Month for the selected Club), and doesn't present the same strange behavior after a destroy... and both have an almost identical ExpList declaration in their original xml layout so... well, perhaps tomorrow morning I'll see the light, but if anyone has an idea, feel free :D
The more I write, the more I think I should first clear the ExpList but... I don't see how exactly. I've tried
listClubs.removeViewsInLayout(0, listClubs.getCount()) ;
but it just doesn't seem to do anything.
Thanks in advance
Nothing related to Android behavior - I was recreating everytime the whole set of BO behind if the base ArrayList of Districts was not null... instead of simply getting out of the method, but it raises another question - how was the state of this ArrayList, which is declared in a subclass of Application serving as Application in my manifest ? I'll have to make some tests about that...
I know this is a fundamental java question, but i am relatively new to java.
How do i structure the code attached (monitoring) within a UI.
What the code does is just log values, and if certain conditions are activated, it does stuff. The loop () method does pretty much everything, but there are a few small things done by the preceding methods.
Let's say in the UI, I have a 'calibrate' button, which if pressed, runs a calibrate method/thread, and a 'monitoring' button which runs a different 'monitoring' method/thread. The problem is, these methods/threads are at the moment defined in their own project as classes. My ideas are along the lines that i need to construct these 2 classes and then call the methods i want from them in response to UI interaction. However, if i call just the method, for example:
if (monitoring button) {
monitoring.method1;
}
this means that i can't do anything in parallel to that, so I need to make what happens in those classes into thread somehow.
Cheers,
Rokky
Take a look at AsyncTask, this will allow you to run logic in a background thread, leaving your activity free to respond to the user.
I don't think my future lies in Android development, as I am consistently failing at the simplest things...
I've got a button with the label "Game Slot 1". When the user clicks it, I succesfully take them through a couple of activities in which they create a new character. I save the game name in an SQLite database, and the next time I launch my app, I can quite happily dynamically change "Game Slot 1" to the name of that slot's game from the database. Perfect.
But how on earth do I get it to update the view in the same manner when I return to that activity via the back button, or having called finish() on all the subsequent activities?
I'm sure it's something to do with onResume(), and maybe invalidate(), but I just can't seem to find an example.
Is invalidate overkill just to refresh a few UI elements onResume()?
How the heck do you use it, anyway, even if it is?
Is there a better way?
Many thanks in advance for any help offered...just try not to laugh at how simple this probably is! :)
Cheers,
James
That sounds like something you could do in onResume, just query the database and call setText on the element of interest. You should not need to explicitly call invalidate.
I have three simultaneous instances of an AsyncTask for download three files. When two particular ones finish, at the end of onPostExecute() I check a flag set by each, and if both are true, I call startActivity() for the next Activity.
I am currently seeing the activity called twice, or something that resembles this type of behavior. Since the screen does that 'swipe left' kind of transition to the next activity, it sometimes does it twice (and when I hit back, it goes back to the same activity). It's obvious two versions of the activity that SHOULD only get called once are being put on the Activity stack.
Could this be from both onPostExecute()s executing simultaneously and both checking the flags each other set at the exact same time? This seems extremely unlikely since two processes would have to be running line-by-line in parallel...
*****EDIT*** A lot removed from this question since I was way off in what I thought was wrong. Nonetheless I found the answer here quite useful, so I have edited the question to reflect the useful parts.
The only way I can find that this is
possible is if both AsyncTasks'
onPostExecute() executed SO
simultaneously that they were
virtually running the same lines at
the same time, since I set the
'itemXdownloaded' flag to true right
before I check for both and call
startActivity().
Since they are both called on the main application thread, that's not possible, unless you're doing something really strange.
I would introduce some Log calls to ensure that you are not misreading the symptoms.
Beyond that, it is difficult to see any problems from your pseudocode, unless there's a possibility of other downloadID values beyond the three shown. For example, if there is a DL4, and DL4 completed after DL1 and DL2, DL4 would trigger your activity.