Question

I'm developing a game by Andengine for Android. I decided to use SharedPreferences to save levelunlock data, highscore data and so on. I achieved to save data but when I open my game again, it is reseting its data to initializing data.that's why all levels are locked even if user pass some of them.

I use this class:

package com.example.aaa.extras;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

public class UserData {

    private static UserData INSTANCE;

    private static final String PREFS_NAME = "GAME_USERDATA";

    /* These keys will tell the shared preferences editor which data we're trying to access */

    private static final String UNLOCKED_LEVEL_KEY = "GAME_USERDATA";
    private static final String SOUND_KEY = "soundKey";
    //private static final String LIFE = "playerHealth";
    private static final String HIGHSCORE = "GAME_USERDATA";
    private static final String EDITED[] = {"GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA"};
    /* Create our shared preferences object and editor which will be used to save and load data */

    private SharedPreferences mSettings;
    private SharedPreferences.Editor mEditor;

    //keep track of max unlocked level
    public int mUnlockedLevel = 1;  //public int mUnlockedLevel = 5;


    //keep track of player high score
    public int mHighScore = 0;

    public boolean mEditedLevel[] = {false, false, false, false, false, false};

    //keep track of player health
    //public int health = 100;


    //keep track of whether or not not sound is enabled
    private boolean mSoundEnabled;

    UserData() {

    }

    public synchronized static UserData getInstance() {
            if (INSTANCE == null){
                    INSTANCE = new UserData();
                    Log.v("","Creates a new instance of UserData");
            }
            Log.v("","returns the instance of UserData");
            return INSTANCE;
    }

    public synchronized void init(Context pContext){
            if (mSettings == null){
                    mSettings = pContext.getSharedPreferences(PREFS_NAME, pContext.MODE_PRIVATE);

                    mEditor = mSettings.edit();

                    mUnlockedLevel = mSettings.getInt(UNLOCKED_LEVEL_KEY, 1);
                    mHighScore = mSettings.getInt(HIGHSCORE, 0);
                    mSoundEnabled = mSettings.getBoolean(SOUND_KEY, true);
                   for(int i=0;i<6;i++)
                       mEditedLevel[i] = mSettings.getBoolean(EDITED[i], false);

                    Log.v("","Set up initial values for UserData " + mUnlockedLevel + " " + mHighScore + " " + mSoundEnabled);
            }


    }

    public synchronized int getMaxUnlockedLevel() {
            return mUnlockedLevel;
    }

    public synchronized boolean isSoundMuted() {
            return mSoundEnabled;
    }

    public synchronized int getHighScore() {
            Log.v("","HighScore before increment " + mHighScore);
            return mHighScore;
    }

    public synchronized boolean getEdited(int i) {
        Log.v("","mEditedLevel before increment " + mEditedLevel[i]);
        return mEditedLevel[i];
    }

    public synchronized void unlockNextLevel() {
            mUnlockedLevel++;
            mEditor.putInt(UNLOCKED_LEVEL_KEY, mUnlockedLevel);
            mEditor.commit();
    }
    public synchronized void setSoundMuted(final boolean pEnableSound){
            mSoundEnabled = pEnableSound;
            mEditor.putBoolean(SOUND_KEY, mSoundEnabled);
            mEditor.commit();
    }
    public synchronized void setHighScore(final int newHighScore){
            mHighScore = newHighScore;
            Log.v("","mHighScore is " + mHighScore);
            mEditor.putInt(HIGHSCORE, mHighScore);
            mEditor.commit();
    }
    public synchronized void setEdited(int i, final boolean newEdited){
        mEditedLevel[i] = newEdited;
        Log.v("","mEditedLevel is " + mEditedLevel[i]);
        mEditor.putBoolean(EDITED[i], mEditedLevel[i]);
        mEditor.commit();
}
}

And I create and init() it in startActivity(first activity) like this:

   public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) throws IOException
{
    SceneManager.getInstance().createSplashScene(pOnCreateSceneCallback);
    UserData userData = UserData.getInstance();
    userData.init(this);
}

And I use it in any class that I need to use like this:

    UserData.getInstance().setEdited(0, true);
    UserData.getInstance().getEdited(0));
Was it helpful?

Solution

SharedPreferences is a Map of key/value pairs, and you can't have duplicate keys. You are using the same key for many items, so only one key/value pair will be written later:

private static final String UNLOCKED_LEVEL_KEY = "GAME_USERDATA";
private static final String SOUND_KEY = "soundKey";
private static final String HIGHSCORE = "GAME_USERDATA";
private static final String EDITED[] = {"GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA", "GAME_USERDATA"};

And then, on first run, initialising settings with default values - since you have not written them yet (see comments in the code):

public synchronized void init(Context pContext){
    if (mSettings == null){

        //use static Context.MODE_PRIVATE, instead pContext.MODE_PRIVATE
        //as an argument in getSharedPreferences
        mSettings = pContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);

        mEditor = mSettings.edit();

        //same key used for level, highscore, and editedlevel
        //which means all these variables will have the same value determined by "GAME_USERDATA" key
        mUnlockedLevel = mSettings.getInt(UNLOCKED_LEVEL_KEY, 1);
        mHighScore = mSettings.getInt(HIGHSCORE, 0);
        mSoundEnabled = mSettings.getBoolean(SOUND_KEY, true);

        for(int i=0;i<6;i++)
           mEditedLevel[i] = mSettings.getBoolean(EDITED[i], false);

        Log.v("","Set up initial values for UserData " + mUnlockedLevel + " " + mHighScore + " " + mSoundEnabled);
    }
}

I don't see any code that would later commit these values, so if it's missing (eg. you don't use mEditor.commit()), these will always get default value.

Moreover, as mentioned in the first paragraph, for items where you use GAME_USERDATA, you will have only one key/value pair in settings.

Change your keys to be unique:

private static final String UNLOCKED_LEVEL_KEY = "unlocked_level_key";
private static final String SOUND_KEY = "soundKey";
private static final String HIGHSCORE = "highscore";
private static final String EDITED[] = {"ed1", "ed2", "ed3", "ed4", "ed5", "ed6"};

Then call unlockNextLevel(), setSoundMuted(), setHighScore(), setEdited() whenever you want to save a different value of each variable into the settings file, and next time during init(), you will have the values as they were saved.

OTHER TIPS

Inside Init Method: Context.MODE_PRIVATE

mSettings = pContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);

and delete edit() than you are reading, only for writing:

mEditor = mSettings.edit();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top