8

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 ...

caw
  • 30,999
  • 61
  • 181
  • 291

6 Answers6

5

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 ).

Community
  • 1
  • 1
Leonidos
  • 10,482
  • 2
  • 28
  • 37
  • Thank you! I definitely need this piece of information in my `Activity` during its normal life cycle. But why should I prefer `onRetainNonConfigurationInstance()` (which is deprecated) to ` onSaveInstanceState()` (which is really called whenever Android kills an `Activity` and it is not manually killed)? – caw Jan 23 '13 at 10:53
  • Thanks, so I could use something like this? `public Object onRetainNonConfigurationInstance() { mActivityRestarting = true; return null; }` – caw Jan 23 '13 at 12:04
  • I think you can. Try it ) Dont forget to unset mActivityRestarting flag somewhere... – Leonidos Jan 23 '13 at 12:15
3

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.

rekire
  • 47,260
  • 30
  • 167
  • 264
  • Thanks! This is an alternative, of course, but in general, I like Android handling the orientation changes very much. So there's no reason to prevent Android from re-creating the `Activity`. It's just that I want to know if the `Activity` is going to be re-created or simply killed. – caw Jan 23 '13 at 13:15
  • IMHO the automatic rotation is not helpful at all. I mean the app rotates also if you handle this event. I mean this just avoid the reatart. If you want to prevent that your app rotates you have to define other properties in your manifest. – rekire Jan 23 '13 at 13:19
  • But if you declare layouts, drawables or other resources that depend on the available width, this can only be handled correctly if Android re-creates the view. You know, Android would have to load other resources in that case that match the new width better. – caw Jan 23 '13 at 13:44
  • I had no use case yet where I need to load other ressouces for a rotation except a video player. There I had to avoid restarts so that the player did not need to restart downloading the video. At the first time I read about handling rotation I was sceptic too, did you try it? – rekire Jan 23 '13 at 13:56
2

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.

SirKnigget
  • 3,614
  • 2
  • 28
  • 61
2

Activity has a method called isFinishing() that is probably what you are looking for.

See: https://stackoverflow.com/a/9621078/445348

Community
  • 1
  • 1
cottonBallPaws
  • 21,220
  • 37
  • 123
  • 171
  • Thank you! If it was what it says in the other question, it would be exactly what I need, yes. But from the documentation, I definitely understand that you can use it in `onPause()` (or `onStop()`) only to determine if the app simply goes to the background (e.g. via home key) or if it's being destroyed (i.e. it's `onDestroy` is called, e.g. via return key). Thus `isFinishing()` should always be `true` in `onDestroy()`, because if it has reached that method, the `Activity` *is* actually finishing. – caw Jan 30 '13 at 00:34
1

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.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • Thank you! I don't really think so, actually I like Android doing the config changes. Isn't this the way it is actually intended, except for some cases where you really need to handle those changes yourself? – caw Jan 21 '13 at 05:17
  • I'd say the vast majority of non-trivial apps override configChanges. Most of google's own software does, including their browser. Google Maps API requires you to do so. Note that even overriding it will still make it correctly resize your views. I think its something that let them be lazy on some trivial apps early in Android development which they never removed and are now stuck with. Or that someone high up in the dev team liked and got political. I think the only thing it helps is automatically changing to landscape resources if you have landscape folders. – Gabe Sechan Jan 21 '13 at 05:24
  • Who downvoted this answer now without providing an alternative? I just started to like this solution. But I've just found the passage in the docs again: `Note: Using this attribute should be avoided and used only as a last-resort.` http://developer.android.com/guide/topics/manifest/activity-element.html – caw Jan 21 '13 at 15:22
  • I had someone going around and downvoting all my posts. I apparently pissed someone off. And according to a mod, not the guy I originally thought. – Gabe Sechan Jan 21 '13 at 15:44
0

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 .

android2013
  • 415
  • 2
  • 5
  • Sorry, `onPause()` is no alternative. You should see that if you read the question correctly ;) `onPause()` is *always* called when the `Activity` closes, also when the user opts to leave. This is exactly what I do not want. `onNewIntent()` is not possible, either, as the `Activity` *is* destructed and re-created when the device is rotated. – caw Jan 25 '13 at 16:32
  • 2
    If user has finished the game (using exit button) you can put a logic there , if the user has finished the game using back key override the back key button in your main activity and save your state there , otherwise in any other cases it is system which has destroyed , the above ways work because onSaveInstanceState() is not guaranteed to be called at all ,also Once your activity is stopped, the system might destroy the instance if it needs to recover system memory. In extreme cases, the system might simply kill your app process without calling the activity's final onDestroy(). – android2013 Jan 28 '13 at 06:33
  • Yes, `onSaveInstanceState()` might not be the best solution. But what about `onRetainNonConfigurationInstance()`? – caw Jan 28 '13 at 13:04
  • This will be the case for config changes only , the best bet it override back key in main activity and you will know if user has pressed back to finish it. – android2013 Jan 29 '13 at 05:39