I had assumed that when an app is pushed to the background or the user hits the back button, that it can later be resumed in the last state that it was in, because this seems to be what most apps do. But after reading about the activity lifecycle, it appears that this mostly has to be done manually.
What would be the least complicated way to achieve this for a game? Is serializing most of the game state something to look at? Is there some tutorial on the specifics of this topic? it seems like there is an awful lot of various data in my game that i would have to save in order to recreate the game state.
LibGDX should handle most of that for you, as far as I can remember. The only thing you need to watch for is unmanaged textures (textures that are generated at run time or have changed since they were loaded in initially). But if you don’t mess with your textures they are actually managed internally by GDX. What kind of data are you working with?
Also, just so you know when the user hits the back button on Android, the app is sent into a very weird state. The app may be eaten by the GC and the memory released back to the Android framework for use by other apps. Special steps are needed when dealing with the back button, although the home button doesn’t do the same thing.
hmm youre right, the home button works -the game gets restored. the back button just kills it.
the only data im working with is basic game state variables and arrays of objects which there are many of … but then theres things like which libgdx screen is currently set…
it seems like the home button is putting the game into the stopped state, not actually calling onSaveInstanceState().
back is destroying the app, which would call onSaveInstanceState() which is where i need to add in my own state data… it would be nice if there was a fully automated way to do this, but then some apps could have GB of data in memory which doesnt need saving to disk, and it wouldnt know how to decide which things to save.
savedInstanceState.putInt() is expecting key/value pairs, this isnt going to work for saving the state of my world map… perhaps this is a case of “it would be easier if i had read about this before even starting my project”
I’ll take my game Nekronoid as an example, I was thinking of implementing some way of saving the state to prevent the recycling of the activity when the user opens a lot of apps. In my game I don’t need a lot of data, just the player info (size, velocity, ball velocity, current weapons, lifes and I think that’s all), current stage info, and “accumulated” info (basically scores). From my point of view, there are things “not so important”, like music exact position, animations time elapsed, etc. so I would just not save this data.
I don’t know how many info are you saving, but if you make it a little bit simpler or just forget things like I was going to do you will be able to resume your game… What kind of game are you developing??
By the way, did you try overriding back button functionality? I don’t have enough experience with libgdx so I can’t help you with that, but if home button is working maybe you can try to mimic its behaviour…
basically we want to save all the dynamic data necessary to recreate the game state… im not quite sure yet whether to do this in the pause() method, or in the destroy() method…
and then to reload it all, i think, in the create() method. it now seems obvious that when my app starts, it starts from the begining when the create() method is first called, because there is nothing there to put it back to its former state after having been destroyed.
this comes down to planning from the begining and knowing what data you will need to save, so that it is easy to save. and also designing your classes so that there is a minimum of data that needs to be saved. it is a bit confusing how the home button puts the game in the background, where the back button destroys it, it seems more natural for the opposite to happen.
Don’t forget that in the Android world apps can get destroyed without any notification - do not rely on onDestroy ever being called. It is best to persist your app state as early as possible to avoid losing data. Also note that it’s best to spot equivalent points in any lifecycle at which to build up and tear down. With that in mind:
If you’re working with Activities, I recommend saving state in onPause() and restoring in onResume().
If you’re working with libGDX, there are some very odd decisions they made to do with lifecycles, so tread carefully! Note that lifecycle on desktop is sometimes different from Android. It’s all wonky enough that I wouldn’t be surprised if it all changes in the future, so I recommend logging everything and testing the app flow to see what gets called when for all your target platforms in the version of the library you’re using.
Some specific advice if you’re using Game and Screen in version 0.9.9: in Screen.show() just call Screen.resume(); implement your build up/tear down in Screen.resume()/Screen.pause(); note that Screen.resize() may be called multiple times, and may be called before and/or after Screen.show()/Screen.resume().
The interface is straightforward, but it’s in the implementations and in the Game/Screen structure where I’ve been caught out. If you’d like some specifics, here a few things that have caused me to stumble recently:
On app start, create() is called on the Game, in which you’ll call setScreen() on your first Screen - this calls show() then resize(). Then create() returns and the next line calls resize() on the Game, which calls resize() on the Screen again. Lesson is, you can rely on resize() being called on the Game instance before the Screen almost all the time, just not on first creation.
On Android pressing home then re-running an app is essentially equivalent to minimize/restore on desktop. However, on Android the calls are resize() then resume(), but on the desktop you get resume() then resize().
On desktop, pause() might mean just unfocused, while on Android pause() is seen when the activity moves into the stopped state. An activity in stopped state may be terminated without a call to onDestroy(), so you’ve got to persist any data you need before then, so lesson is to persist in pause() and restore in resume(). But just need to consider that the desktop app may still be visible and rendering in between these calls.
I haven’t dug much into the internals of libGDX so I don’t know for sure, but the second item doesn’t look intentional to me; that’s why I suggested testing lifecycle on the specific platforms and the specific version people are using, just in case this kind of thing changes between releases.