Serialization is incorrect on Android

Hello there.
I want to serialize game data for an Android game. I had to change some things about my first script that was working, but now I have problems with that script.
I am sure there is a much smoother way of doing this:

  1. I want to store my data in a “DataHandleScript” at runtime.
  2. I want to store my data in serialized binary between game sessions.

I tried to strip this whole thing down into one script, but I had some problems. I wanted to be able to call all variables without reference (-> static variables would be easy), but they are supposed to be serializable (so static is not possible).

Example:

SaveValues.highscore = x;  //or SaveValues.Instance.highscore
SaveValues.Save();

I’ve tried following multiple tutorials, but they didn’t guide me to the solution I wanted, therefore I tried changing their suggestions a little. Only problem is that if I load another scene or reopen the app, the values have randomly increased a lot (e.g. from 115 scored points to 22.465).

This is the main part of my Saving Script:

[System.Serializable]
public static class SavingValues
{
		
public static SaveValues Instance;

void Awake(){
	Instance = this;
}

public void Load()
{
	if (File.Exists(Application.streamingAssetsPath+"/SaveFile.bfp"))
	{
		SaveValues.Instance.data = SaveData.Load(Application.persistentDataPath+"/"+SaveValues.Instance.fileName+".bfp");
		
		SaveValues.Instance.highscore = SaveValues.Instance.data.GetValue<int>("Highscore");
		SaveValues.Instance.collectedPoints = SaveValues.Instance.data.GetValue<int>("CollectedPoints");
		SaveValues.Instance.shopUnlocked = SaveValues.Instance.data.GetValue<bool>("ShopUnlocked");
		SaveValues.Instance.lifetimeScore = SaveValues.Instance.data.GetValue<int>("LifetimeScore");
	}
}

public void Save()
{
	SaveValues.Instance.data = new SaveData(SaveValues.Instance.fileName);
	
	SaveValues.Instance.data["Highscore"] = SaveValues.Instance.highscore;
	SaveValues.Instance.data["CollectedPoints"] = SaveValues.Instance.collectedPoints;
	SaveValues.Instance.data["ShopUnlocked"] = SaveValues.Instance.shopUnlocked;
	SaveValues.Instance.data["LifetimeScore"] = SaveValues.Instance.lifetimeScore;
	
	SaveValues.Instance.data.Save();
}

public void Reset(bool firstStartDone)
{
	SaveValues.Instance.data = new SaveData(SaveValues.Instance.fileName);
	
	SaveValues.Instance.data["Highscore"] = 0;
	SaveValues.Instance.data["CollectedPoints"] = 0;
	SaveValues.Instance.data["ShopUnlocked"] = false;
	SaveValues.Instance.data["LifetimeScore"] = 0;
	SaveValues.Instance.data["FirstStartDone"] = firstStartDone;
	
	SaveValues.Instance.data.Save();
}

And this is my DataHandleClass:

[System.Serializable]
public class SaveValues
{
	public int highscore = 0;				//saved Highscore
	public int collectedPoints = 0;			//Points collected on this account
	public bool shopUnlocked = false;		//Is shop unlocked
	public int lifetimeScore = 0;			//count of all points ever collected
	
	public string fileName = "SaveFile";	        //name of the save file
	private SaveData data;				//save data variable
}

in the same script.
I hope you can show me a better way of archieving my goal or find the reason for this script to strangely increasing my values.
Please help me, I have made great progress in my game but I’m stuck with this problem for a few weeks now and I can’t find a proper solution.

Thanks in advance.

A common implementation is to use a simple singleton class for both, storing the values with a BinaryFormatter and provide global access to those values.

//SaveLoadManager.cs
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

[System.Serializable]
public class SaveValues
{
    public int highscore = 0;
    public int collectedPoints = 0;
    public bool shopUnlocked = false;
    public int lifetimeScore = 0;
    public bool FirstStartDone = false;
    private static string m_DefaultFileName = "SaveFile.bfp";
    private static SaveValues m_Instance = null;
    public static SaveValues Instance
    {
        get
        {
            if (m_Instance == null)
            {
                if (!Load())
                {
                    m_Instance = new SaveValues();
                    Reset();
                }
            }
            return m_Instance;
        }
    }
    public static void Save()
    {
        Save(Application.streamingAssetsPath + "/" + m_DefaultFileName);
    }
    public static void Save(string aFileName)
    {
        using (var stream = File.OpenWrite(aFileName))
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, Instance);
        }
    }
    public static bool Load()
    {
        return Load(Application.streamingAssetsPath + "/" + m_DefaultFileName);
    }

    public static bool Load(string aFileName)
    {
        if (!File.Exists(aFileName))
            return false;
        using (var stream = File.OpenRead(aFileName))
        {
            var formatter = new BinaryFormatter();
            m_Instance = (SaveValues)formatter.Deserialize(stream);
        }
        return true;
    }
    public static void Reset()
    {
        Instance.highscore = 0;
        Instance.collectedPoints = 0;
        Instance.shopUnlocked = false;
        Instance.lifetimeScore = 0;
    }
}

public class SaveLoadManager : MonoBehaviour
{
	void Awake()
    {
        SaveValues.Load();
	}
}

Here you can access your values from everywhere using:

SaveValues.Instance.highscore = 6;

If you don’t like the “Instance” in between, you can add static properties for all your values like that:

public static int highscore
{
    get { return Instance.highscore; }
    set {Instance.highscore = value; }
}
//...

***edit ***
Fixed an issue that would result in a stack overflow when the save files doesn’t exist yet ^^.

I’ve figured it out. My problem wasn’t this script (although It would have been a problem too ^^).
In a FixedUpdate()-Function of mine a script has done this:

void FixedUpdate ()
	{
		if (gameover == true)
		{
			scoreText.text = "Score: " + score; 															
			GameOverText.text = "GAME OVER"; 																
			FinalScoreText.text = "You've earned " + score + " points.";													
		Instance.collectedPoints += score;
		SaveValues.Save();
		}
	}

Which ultimately leads to a repeated addition of the score to the collectedPoints variable until I load another scene. I’ve fixed that and now it works!

Thanks though, @Bunny83, your answers were extremely helpful too.