I am wondering what strategies others use to avoid data loss when saving files on Android. I have a couple of game apps that and essentially, they potentially save the game stat
We've had occasional issues when we're doing I/O (usually writing) to persistent storage (private filesystem on internal memory) from the main thread. Usually this doesn't take much time at all, but occasionally it inexplicably takes ages (20 or 30 seconds or more). It seems that the Android filesystem implementations on some devices don't support concurrent access (see this, so your I/O can block if another process is using the filesystem. If you are doing your I/O on the main thread, the OS can/will kill your Activity if it blocks for too long. This may be what is happening to you.
Due to this problem, I would suggest that you move all your I/O to a separate thread (not the main thread). So, for example, to save the game state, in onPause() call a method that serializes the game state to a ByteArrayOutputStream which you then hand off to a separate thread to be written eventually to the filesystem.
If possible use SharedPreferences
to store your game state. Your changes will be committed only after you call commit()
. You can do the saving in onSaveInstanceState
callback. Read the docs here.
This sounds like a good job for a service.
http://developer.android.com/reference/android/app/Service.html
First off I would try to see if the app is really killed without notification because I don't think that should be the case. Apps might be stopped for something like a phone call but I don't really think android is just killing it without any notification at all. It could decide to end it, but not without saving the state, etc.
Maybe there is just an error that occurs with the saving itself.
A way that does not require much modification to check that would be to use a checksum or use some other way to verify the integrity of the saved data (size, ending marker, etc.). All you have to do is save it, read it and check it (log any mistakes) and repeat that until its correct. It might not be that good if you save large amounts of data, but for mere gamedata it should be all right.
You could also set a state when the app starts and ends, and then you would know on the next start if it ended correctly the last time or not and if you have to take extra measures.
I think that saving little portions of data (not the whole game state) to the database every time user performs any action (not only when onPause()
is called) would be the best approach in this case. However, this may require a lot of modifications to the code.
The compromise would be to split the game state into smaller portions or sub-states (let's say, round1
, round2
, ..., players
, etc) and again store data to appropriate files as user performs any action, not waiting for onPause()
call. This would significantly reduce the probability of loss and at least would guarantee that the user doesn't loose the whole game progress. Moreover, to avoid inconsistent states of your app, which may appear when the save process is interrupted, you'd better save data to temporary file first and only in case of success simply rename the file, not copying its content (let's say, round1.xml.tmp
rename to round1.xml
).