7

I've been investigating alternative methods for saving my game's data between turns, and wonder if anyone can point me in the right direction.

I have approximately 32k of data which must be saved during onPause. I ruled out preferences due to the sheer quantity of data. I spent a few days playing around with SQLite but couldn't get the data to save in less than two seconds (although the time certainly hasn't been wasted).

I've decided that I'll use the database for loading constant data at the beginning of the game. This will certainly make it easier to tweak various parameters and default values in the game. But this still leaves me looking for the ideal method for writing data.

The data that needs to be saved is basically nine occurrences of class A and nine occurrences of class B. I'm an intensive month into the learning curve of Android (and the nuances of Java, coming from a C++ background) and have been googling like crazy. This brought two possibilities to mind -

1) Serialization (ObjectOutputStream)

I thought this would be the perfect solution but, having read several other posts regarding the subject, gather that it isn't highly recommended on the Android platform due to speed and memory allocations provoking the garbage collector into a potential rage.

2) DataOutputStream class

My current thought is to add Load and Save functions to both classes and to use DataOutputStream and DataInputStream calls in them to write and read the data respectively.

The data in the classes are primitives (strings and ints mostly) and arrays of primitives, so there's nothing too complicated in there to break down. Would this second solution seem a good, viable one? Or are there other solutions that I am unaware of as yet?

Rok
  • 2,568
  • 4
  • 26
  • 28
  • The main consideration to take into account is that writing to flash can be a long operation, irrespective of the size of the data. Even writing 1 byte can take a noticeable amount of time. So make sure your solution buffers up all the data and writes it in as few operations as possible. – Jems Feb 10 '11 at 20:48
  • 1
    Thanks for the advice. I've gone with the DataOutputStream method and the time taken to write the data is now negligible (approx 0.1 seconds). I'm glad I got sidetracked with SQLite databases though, as they're sure to come in very useful, too :) – Rok Feb 10 '11 at 22:03

4 Answers4

2

Why do you have a 2 second limit on your database write? If it is purely for the sake of UI responsiveness, then there is another approach you can take.

You don't actually have to perform the save within your onPause method itself, you could just kick off a new Thread that actually does the save for you.

private void backgroundSave(){
    Thread backgroundThread = new Thread() {
        @Override
        public void run() {
            //do save here
        }
    };
    backgroundThread.start();
}

@Override
protected void onPause() {
    super.onPause();
    backgroundSave();
}

You could alternatively use an AsyncTask for this.

You might have to consider the case when a user attempts to restart your app before the save is complete, but that shouldn't be too hard to take into account.

dave.c
  • 10,910
  • 5
  • 39
  • 62
  • 1
    The data being saved is in constant use throughout all activities. The idea of assigning the save to a background thread sounds a good one, but I haven't had time yet to familiarise myself with solving synchronization issues. It's something I will definitely look into as soon as I get the chance. For now, I've found that I can write the data in a binary file in around 0.1 seconds. I do appreciate the advice though. So much to learn, so little time... :) – Rok Feb 10 '11 at 22:00
2

You should use an Async task to save the data, I used this method to fetch highscores at the start a game:

new HighscoreTask().execute(this);

the Async task looks like this:

public class HighscoreTask extends AsyncTask<MainView, Void, Void> {

    protected void onPreExecute() {
    }

    protected void onPostExecute(final Void unused) {
    }
    @Override
    protected Void doInBackground(MainView... params) {
        HighScoreFactory.syncScores();
        return null;
    }
}

All the database interaction happens in HighScoreFactory.syncScores() this can take as long as it needs because it happens in the background. In my case it sends an HTTP request to an external server and loads these into a database. It's never caused any problems and works seamlessly.

Kevin
  • 1,200
  • 1
  • 11
  • 19
  • Thanks - I'll certainly keep that in mind. I'm saving the game data as raw binary files now which is working a *lot* faster. But will definitely investigate Async as a few people have suggested it now. – Rok Feb 11 '11 at 00:21
1

Have you tried insert data to the database in transaction?

try{
 db.beginTransaction();

 //here insert data to database    

 db.setTransactionSuccessful();
} finally {
 db.endTranscation();
}

That can speed up operation.

pawelzieba
  • 16,082
  • 3
  • 46
  • 72
  • I experimented with using transactions to the point where all my writes were done in a single transaction - this brought the time down from 8 seconds to 2 seconds. I seemed to hit a brick wall at that point and, give or take a tenth of a second, couldn't get any lower. This is the first SQLite coding I've done, but my feeling was that I couldn't get it any quicker (though I'd be happy to be told otherwise) – Rok Feb 10 '11 at 21:07
0

Create a new Thread that does the data writing using Context.openFileOutput(String name, int mode) with this as the context. You can then write it in the background with the new thread and retrieve it with: Context.openFileInput(String name) again with this as the context. Hopefully this helps.

eosgood
  • 318
  • 1
  • 9