I'm learning about android programming from official website(http://developer.android.com).
I understand most of life cycle, but I'm not sure when system is destroying activity.
From what I understand, system is destroying activity when some activity stays for longer time in onStop() or when foreground activity needs more resources. Is that right ?
And from what I read the most efficient way to update data base is in onStop(), but let's say user is adding one word to my 'dictionary' application. So I need to gather this words in list and then update data base? Or I should insert rows to DB with each word ( in other method ) ?
As i understand you will never know when android force your application to stop.
So it is like this
onCreate() // here you could initialize
This is safe
onResume() // here turn on
onPause() // here turn off
// After this it is not sure
But if you are sure that finish() is always called you could use others
Data has to be persisted in the onPause()method. Otherwise, the system might terminate your process without further notice.
Related
For online games, it would be great to know if an Android Activity's onDestroy() is only called because Android is going to re-create it (e.g. device rotation) or if the user opted to exit the game.
My plan was to set a flag in the Activity's onSaveInstanceState() when Android is probably re-creating the Activity:
private boolean mDestroyedForReCreation;
...
protected void onSaveInstanceState() {
...
mDestroyedForReCreation = true;
}
If you did this, you can check mDestroyedForReCreation in onDestroy():
If the flag is set (true), don't dismiss the user from the online game.
If the flag is not set (false), dismiss the user from the online game as he did voluntarily exit the game.
Is that a correct approach? And if yes, is it recommended or is there any better solution? I hope so because I don't really like that solution ...
I suggest you to remove such kind of game logic from activity's life cycle. Create a Service. If no one binded - all activities are dead. Is someone binded - keep working.
If you do not want to create service, you can use onRetainNonConfigurationInstance method. Here is example.
You should use onRetainNonConfigurationInstance because it is called by the system, as part of destroying an activity due to a configuration change, when it is known that a new instance will immediately be created for the new configuration. onSaveInstanceState called when android going to kill activity and maybe restore it sometimes or maybe not ).
You can simply avoid restarts on rotation by handling this configuration changes by code. You can do this in your Manifest.xml like this:
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
android:label="#string/app_name" >
So your app won't restart on rotation and if the keyboard opened/closed.
I think this solution is much simpler.
In this case you almost don't need to handle onSaveInstanceState() for exiting, except you start another intent/activity where you need to save your game state. Note that a phone call will also interrupt your code. I know some games with funny bugs where the time is resetted but not the score.
I would just simplify the whole thing, and set a flag that is toggled when the user exits the game, something like:
void exitGame() {
mUserExited = true;
finish();
}
(Or you might need more logic if you need to destroy multiple activities)
Then check the flag in onDestroy().
Whatever logic you have about configuration changes (rotation, etc.) will have nothing to do with the exit game flag.
Also, remember that the 'back' button's default behavior is to finish() the current activity (if nothing else is above it) - that won't count as an "exit" in this case. The behavior here is up to you.
Activity has a method called isFinishing() that is probably what you are looking for.
See: https://stackoverflow.com/a/9621078/445348
If you need to know this, you should consider handling rotation and other configuration changed events yourself rather than letting the system do it. If you set in your manifest that the activity handles configChanges, it will call onConfigChange when it rotates rather than destroying and recreating the activity. A large amount of apps do this, the whol destroying and recreating on rotation thing Android does is absolutely retarded.
onRestoreInstanceState() will be called if when it is restored /recreated , if the activity if killed by android it saves its activity UI state and some values you can override onSaveInstanceState
but because onSaveInstanceState() is not guaranteed to be called, you should use it only to record the transient state of the activity (the state of the UI)—you should never use it to store persistent data. Instead, you should use onPause() to store persistent data (such as data that should be saved to a database) when the user leaves the activity. Also onRestart will be called after onStop() when the current activity is being re-displayed to the user. So probably you can save your state in onPause / if onRestart is called it is like it is being re displayed , while if onCreate is called without onRestart it is recreated . Other solution is to use singleInstance and override method onNewIntent which is called if activity is not destructed but like restarted on a new intent .
I need to know when an application finishes to stop all the local services that it starts.
How can I do it?
You could try using onDestroy() (not recommended, though) to know when Android is cleaning your app from the memory. or can also use onStop() to know when the Activity is being sent in the background.
Do implement these two methods in the first activity of the Activity stack.
Lets see if it helps, since I also haven't tried it so far.
One idea is to use BoundService despite the fact that it's your app own service. By definition Bound Service stops when the las connection is dropped.
Another idea would be to define count in Application object (you can override global Application object). You can increment the count in each onResume and in decrement in each onPause.
You could use try / finally on the main function and do the service clean up in the final block
You could use object finalizer to issue shutdown commands. You wont know exactly when it happens since the Garbage collector will run at its own pace, but you do know it will happen eventually.
I am now solving the same problem, I have an Idea and will implement it:
1.static variable called (String currentShownActivity).
2. in every Activity (onResume() ) I fill the variable with activity name). So when I navigate between the activities the currentShownActivity variable changed and carry the current activity name.
3. on every onPause(), set flag that indcate the activity onPause() called (i.e boolean IsPauseCalled)
4.in onStop () check IsPauseCalled, and the activity name.
if the activity onPause called and the name in currentShownActivity not changed (that mean we leave the activity to "no activity") and that mean [home] key pressed.
the integration way to know the the application is not running Check onDestroy of the main activity.
My app is retaining all of the variable values when it closes and this is effecting how it runs when reopened. Is there any way to reset them all upon app close? or is there a way to clean the app from memory when it is closed so to speak? For the moment I have just been setting all of the important variables "=0" in the last few lines of execution but I know there must be a correct way to doing this.
EDIT:
OK I thought that it would just be easier to reply here instead of individually to everyone.
The app is indeed staying alive in the background, I checked with advanced task killer. How would I get the ap to "Die" by presing the back button? I think this would be the easiest solution given how the app works:
open app > press start button > press stop button > results screen > press back button to exit.
so basically each time the app runs should be an independant execution.
Override the onPause, onResume, and onDestroy methods. onPause should save anything upon pausing, onResume should reload these values when it is resumed, and onDestroy will be called when your app closes. You can clean up stuff in onDestroy. See this link.
You app is probably not closing but remaining in background. Check advanced task manager and see if the app is running or not.
You need to familiarize yourself with the Activity Lifecycle.
You could leverage onResume() to reset your variables; also note onDestory() and onPause().
UPDATE:
Killing the application in its entirety each time the app moves to the background is an anti-pattern. You should really look at your application and follow the aforementioned activity lifecycle pattern and take the needed steps to insure your variables exist as you desire based on state.
I like what #Alex and #Jack said. To add to that, also consider that you can call finish() in your Activity if you want to force it to close up and return to the last Activity. Going along with this, also consider the use of setResult(int) (JavaDoc Here)
You can also set a flag on the Intent when you call the Activity you are questioning about. A flag like FLAG_ACTIVITY_NO_HISTORY could be helpful:
If set, the new activity is not kept in the history stack. As soon as the user navigates away from it, the activity is finished. This may also be set with the noHistory attribute.
List of Intent Flags
Uninitialized variables are bad. Don't do it. ALWAYS manually reset variables before using them for the first time.
the onResume() method will let you reset the variables when the program resumes, but will also do it when you return to the activity unless you add the logic that says you are coming from in the app, not the home page. Maybe onRestart() is what you really need? I'm not positive, but it's possible with onResume.
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.
According to the "Application Fundamentals" article, section "component lifecycle", onResume() is always called when a View becomes active, independent of the previous state.
In the Notepad tutorial, Exercise 3, I have found something confusing in NoteEdit.java:
There is a call to populateFields() in onCreate() as well as in onResume().
Wouldn't it be enough (or even better) to have it only in onResume() ?
In such a small example, it will not do any harm if populateFields() is performed twice, but in a bigger App, things can be different ...
Thanks and Regards,
Markus N.
From a look at Notepad3, I would say you are correct. There doesn't seem to be any reason for them to call populateFields() in both onCreate() and onResume(). onResume is sufficient.
I can see where you need it in both places, if application pauses then you would need it in onResume and if your process gets killed or user navigates back to activity then you will need it in onCreate especially if you are doing some pre-processing.
Per the documentation....for onResume() they recommend using it for lightweight calls unlike in onCreate():
"The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time the activity is in front of all other activities and interacting with the user. An activity can frequently go between the resumed and paused states -- for example when the device goes to sleep, when an activity result is delivered, when a new intent is delivered -- so the code in these methods should be fairly lightweight. "
The Notepad app may want a variable declared if the method was already hit by onCreate not to redo in onResume().