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.
Related
Why Is onCreate() Preferred To Do All The Main App Tasks? Why not onResume() or onStart()? Why only onCreate()? I tried to do the main tasks like binding findViewById() setting text to text views and a lot more. They all work fine. When why do we always are preferred to do that task in onCreate()?
OnCreate serves as the first entry point into your activity, so logically it makes sense to do as much of the initialization here as possible. Often times there are cases when things need to get configured with higher priority - crash reporting services, dependency injection etc. where this would get escalated to a custom application class.
according to the docs
protected void onCreate (Bundle savedInstanceState)
Called when the activity is starting. This is where most initialization should go: calling setContentView(int) to inflate the activity's UI, using findViewById(int) to programmatically interact with widgets in the UI...
so, I suppose it is fair to say that most initialization will get done inside of onCreate, which usually means that if you were to place this into a lifecycle method which could get executed repeatedly, that could be considered redundant as you'd be assigning the same values to variables repeatedly, unless that's something you actually want to do.
However, lazy initialization is also a concept to keep in mind, being able to initialize something inside of onCreate doesn't always mean that you should, it is often times better to delay initialization until you actually need the instance.
regarding
I tried to do the main tasks like binding findViewById() setting text to text views and a lot more. They all work fine.
they definitely would, findViewById can always be used and isn't limited to being inside of onCreate, in fact the result of findViewById doesn't even have to be assigned to a variable for you to be able to use it
Background
I'm working on making an app better by supporting its landscape mode. One thing that I use a lot is Loaders, or more specifically AsyncTaskLoaders .
Using Loaders allow you to keep doing a background task even if the activity is being re-created due to orientation changes, as opposed to AsyncTask.
The question
I'd like to ask about the lifecycle of Loaders:
When do they get GC-ed ? Do I have to keep track of them, and if one has a bitmap inside, should I abandon it as soon as possible? Do they perhaps get GC-ed only after the activity is really destroyed (and not because of configuration changes) ?
I've noticed they have states of being stopped. Does this somehow allow me to pause them?
If #2 is true, How would I implement a loader that can be paused on some points of itself?
Can fragments also have Loaders? As I've noticed, it's only for activities.
if #4 is false, what is the recommended way to use loaders in the design pattern of navigation-drawer that replaces fragments in the container?
Can AsyncTaskLoader be interrupted like AsyncTask (or threads)? I've looked at its code and at the API, but I can't find it. I've also tried to find a workaround, but I didn't succeed.
If #6 is false, is there an alternative? For example, if I know that the loader doesn't need to load something, I could just stop it right away. One way I can think of is to set a flag (maybe AtomicBoolean, just in case) that will tell it to stop, and check this value sometimes within. Problem is that I will need to add it even inside functions that it uses, while an easier way would be to call "Thread.sleep(0)" or something like that.
Is there somewhere an explanation of the lifecycle of Loaders?
Do AsyncTaskLoaders work together, at the same time, or are they like the default, current behavior of AsyncTask, which runs only on a single thread ?
1.When do they get GC-ed ? Do I have to keep track of them, and if one has a bitmap inside, should I abandon it as soon as possible? Do they perhaps get GC-ed only after the activity is really destroyed (and not because of configuration changes) ?
Since the loader lifecycle is tied to the activity/fragment lifecycle, it is safe to assume that the garbage collection pretty much takes place at the same time. Take a look at #8 for the lifecycle of loaders. Might give you some ideas.
2.I've noticed they have states of being stopped. Does this somehow allow me to pause them?
No, as far as i know loaders do not have a onPause() per say.
3.If #2 is true, How would I implement a loader that can be paused on some points of itself?
I really have no answer to this one. Would like to know a solution to this myself.
4.Can fragments also have Loaders? As I've noticed, it's only for activities.
Of course fragments can have loaders. Just initialize the loaderManager in the onActivityCreated() method
5.if #4 is false, what is the recommended way to use loaders in the design pattern of navigation-drawer that replaces fragments in the container?
4 is true. So this question is irrelevant i guess.
6.Can AsyncTaskLoader be interrupted like AsyncTask (or threads)? I've looked at its code and at the API, but I can't find it. I've also tried to find a workaround, but I didn't succeed.
I am not sure what do you mean interrupting the loaders. But if you mean having something similar to a isCancelled() method, then there is a method called cancelLoad() on the AsyncTaskLoader. The complete flow is like cancelLoad()->cancel()->onCancelled() i think.
7.If #6 is false, is there an alternative? For example, if I know that the loader doesn't need to load something, I could just stop it right away. One way I can think of is to set a flag (maybe AtomicBoolean, just in case) that will tell it to stop, and check this value sometimes within. Problem is that I will need to add it even inside functions that it uses, while an easier way would be to call "Thread.sleep(0)" or something like that.
Irrelevant again?
9.Do AsyncTaskLoaders work together, at the same time, or are they like the default, current behavior of AsyncTask, which runs only on a single thread ?
Runs on a single thread.
8.Is there somewhere an explanation of the lifecycle of Loaders?
To my best of knowledge:
When activity/fragment is created the loader starts -> onStartLoading()
When activity becomes invisible or the fragment is detached the loader stops -> onStopLoading()
No callback when either the activity or the fragment is recreated. The LoaderManager stores the results in a local cache.
When activity/fragment is destroyed -> restartLoader() or destroyLoader() is called and the loader resets.
I hope this helps. I might be a bit off on some of the answers. I am constantly learning new things myself.
Cheers.
Should I let go of views and other data i'm holding on to in onStop() or onDestroy()?
If I release my application's data in onDestroy() it won't be very memory-friendly towards android, am I correct? Since i'm still holding on to a couple of views after onStop(). Plus it's not guaranteed to be called and my Activity is purged from memory anyway.
If I release it in onStop(), I have to add do my setContentView() etc. in onStart() which doesn't get the Bundle that onCreate(Bundle) is handed.
Note that I have a very large application which consists of dozens of Views, most of which are custom and added by code rather than layout-files. This is largely due to the fact that I had to create a custom pager to flip through pages, since none of the built-in Views could serve my purposes (I've tried… hard…).
I have read through all the relevant Android docs but I still have no real clue on what about the view-hierarchy Android saves/recreates by itself and what I have to do myself. Or when all of that happens, meaning when Android removes the view-hierarchy from memory.
Update Question:
The android docs says this: Note: Because the system retains your Activity instance in system memory when it is stopped, it's possible that you don't need to implement the onStop() and onRestart() (or even onStart() methods at all.
If it's ok to hold on to everything, why should I care about memory-leaks when my application is being stopped like this article says? If it's destroyed and re-created, for example after a screen-rotation, I'm starting from scratch anyway?
No, you do not have to let go of anything in onStop() or onDestroy() if you only hold it in your activity (in its non-static fields). When Android let's go of your activity, the rest of your stuff is automatically thrown away (along with the activity), because there is no way to reach it from any thread (this is how Garbage Collectors work, it is not in any way special or specific to activities).
The article you refer to describes the problem where a reference to a view (or a drawable, or - broadly speaking - activity context) survives the activity that created it. Since there is a reference pointing back to the already dead activity, it becomes a zombie; what's more, it clings to all its fields, effectively zombifying them too. So if you have a view or a drawable and put it in a static field (or in any other place that might survive your activity object), then yes, you have to let it go in onStop() or onDestroy() of the relevant activity.
If Android destroys your Activity and forgoes calling onDestroy(), it means that the whole process was taken down, and this means that no memory leak can occur anyway (they are local to a single process)
Bonus answers:
views inflated from XML files take exactly as much memory as ones built in code. Why should they be heavier?
(update, after a comment) before an activity gets thrown away, Android walks its whole view hierarchy and gives each view a chance to store its state (any parcelable data) into a bundle; when recreating view Android walks the tree again and gives the data back. This is why when you recreate an activity the state of the view is saved (focus, position, content of text fields etc.). Observe how the state is only saved for elements that have an id (does not matter if they are inflated or created dynamically).
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
Should you get data via a cursor and fill in the data on the screen, such as setting the window title, in onStart() or onResume()?
onStart() would seem the logical place because after onStart() the Activity can already be displayed, albeit in the background. Notably I was having a problem with a managed dialog that made me rethink this. If the user rotates the screen while the dialog is still open, onCreateDialog() and onPrepareDialog() are called between onStart() and onResume(). If the dialog needs to be based on the data you need to have the data before onResume().
If I'm correct about onStart() then why does the Notepad example give a bad example by doing it in onResume()? See http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html NoteEditor.java line 176 (title = mCursor.getString...).
Also, what if my Activity launches another Actvity/Dialog that changes the data my cursor is tracking. Even in the simplest case, does that mean that I have to manually update my previous screen (a listener for a dialog in the main activity), or alternatively that I have to register a ContentObserver, since I'm no longer updating the data in onResume() (though I could update it twice of course)?
I know it's a basic question but the dialog only recently, to my surprise, made me realize this.
Again the solution depends on what suits you.
If you want the cursor to be pre-populated once per application (and not bothered about any change, then you can do it in onCreate(). This method will be recalled only if the app process is killed and app is reinitiated.
If you want the cursor to be prepopulated everytime the visible lifetime starts (most cases a service/broadcast is calling your activity, you should use onStart()
If you want the cursor to be prepopulated for every foreground lifecyle of activity, you should use onResume(). So if you have a dialog box or another subactivity modifying some information and hence you want to reload the cursor, it is best you do so in onResume(). The downside for this method is everytime the activity comes in foreground the cursor is reloaded.
Hope this makes it clear
To answer your question about NoteEditor, simply take a look at the lines above the one you cite and you'll see...
// Requery in case something changed while paused (such as the title)
mCursor.requery();
The comment seems to explain it all. Although I haven't gone through the NotePad example myself, it appears the author(s) are building in the ability to recover from changes whilst the NoteEditor is paused (and then resumed).
As GSree explains (whilst I was typing this), there isn't a right or wrong answer and it simply depends on what needs to be done at which point of the Activity life-cycle.