Android - SharedPreferences with serializable object

AndroidSerializationSharedpreferences

Android Problem Overview


I know that SharedPreferences has putString(), putFloat(), putLong(), putInt() and putBoolean(). But I need to store an object that is of type Serializable in SharedPreferences. How can I achieve this?

Android Solutions


Solution 1 - Android

In short you cant, try serializing your object to a private file, it amounts to the same thing. sample class below:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import android.app.Activity;
import android.content.Context;

/**
 *
 * Writes/reads an object to/from a private local file
 * 
 *
 */
public class LocalPersistence {

	
	/**
	 * 
	 * @param context
	 * @param object
	 * @param filename
	 */
	public static void witeObjectToFile(Context context, Object object, String filename) {
		
		ObjectOutputStream objectOut = null;
		try {
			
			FileOutputStream fileOut = context.openFileOutput(filename, Activity.MODE_PRIVATE);
			objectOut = new ObjectOutputStream(fileOut);
			objectOut.writeObject(object);
			fileOut.getFD().sync();
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (objectOut != null) {
				try {
					objectOut.close();
				} catch (IOException e) {
					// do nowt
				}
			}
		}
	}


	/**
	 * 
	 * @param context
	 * @param filename
	 * @return
	 */
	public static Object readObjectFromFile(Context context, String filename) {

		ObjectInputStream objectIn = null;
		Object object = null;
		try {

			FileInputStream fileIn = context.getApplicationContext().openFileInput(filename);
			objectIn = new ObjectInputStream(fileIn);
			object = objectIn.readObject();
			
		} catch (FileNotFoundException e) {
			// Do nothing
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			if (objectIn != null) {
				try {
					objectIn.close();
				} catch (IOException e) {
					// do nowt
				}
			}
		}

		return object;
	}

}

Solution 2 - Android

The accepted answer is misleading, we can store serializable object into SharedPreferences by using GSON. Read more about it at google-gson.

you can add GSON dependency in Gradle file with:

compile 'com.google.code.gson:gson:2.7'

Here the snippet:

First, create your usual sharedPreferences:

//Creating a shared preference
SharedPreferences  mPrefs = getPreferences(MODE_PRIVATE);

Saving from serializable object to preference:

 Editor prefsEditor = mPrefs.edit();
 Gson gson = new Gson();
 String json = gson.toJson(YourSerializableObject);
 prefsEditor.putString("SerializableObject", json);
 prefsEditor.commit();

Get serializable object from preference:

Gson gson = new Gson();
String json = mPrefs.getString("SerializableObject", "");
yourSerializableObject = gson.fromJson(json, YourSerializableObject.class);

Solution 3 - Android

If you object is simple POJO you can convert object to JSON string and save it in shared preferences with putString().

Solution 4 - Android

It is possible to do it without a file.

I'm serializing the information to base64 and like this I'm able to save it as a string in the preferences.

The following code is Serializing a serializable objec to base64 string and vice versa: import android.util.Base64;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;


public class ObjectSerializerHelper {
    static public String objectToString(Serializable object) {
        String encoded = null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            objectOutputStream.close();
            encoded = new String(Base64.encodeToString(byteArrayOutputStream.toByteArray(),0));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return encoded;
    }

    @SuppressWarnings("unchecked")
    static public Serializable stringToObject(String string){
        byte[] bytes = Base64.decode(string,0);
        Serializable object = null;
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream( new ByteArrayInputStream(bytes) );
            object = (Serializable)objectInputStream.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (ClassCastException e) {
            e.printStackTrace();
        }
        return object;
    }

}

Solution 5 - Android

We can create an easy to use syntax with Kotlin.

@Throws(JsonIOException::class)
fun Serializable.toJson(): String {
   return Gson().toJson(this)
}

@Throws(JsonSyntaxException::class)
 fun <T> String.to(type: Class<T>): T where T : Serializable {
 return Gson().fromJson(this, type)
}

@Throws(JsonIOException::class)
fun SharedPreferences.Editor.putSerializable(key: String, o: Serializable?) = apply {
   putString(key, o?.toJson())
}

@Throws(JsonSyntaxException::class)
   fun <T> SharedPreferences.getSerializable(key: String, type: Class<T>): T? where T : Serializable {
    return getString(key, null)?.to(type)
}

and then save any Serializable to SharedPreferences using similar get/put()

Complete gist here Save Serializables in Shared Preferences with Kotlin and GSON

As mentioned in other answers, you might have to consider migration when structure of data class changes. Or atleast would have to change key that you use to store.

Solution 6 - Android

2020: If you want to save objects, then it's better to use Proto DataStore instead of SharedPreferences.

It brings great benefits over the “old” SharedPreferences, namely:

  • Async API for storing and reading the data (Flow)
  • Type-safety out of the box (Protocol Buffers)
  • Safe to call from UI thread (Dispatchers.IO underneath)

And many other perks such as transactional API, which guarantee consistency.

Check out my blog post to see how to implement Proto DataStore easily

Solution 7 - Android

If your object is complex with nested objects and you may need to remove a nested object one day then this is a bad mechanism, as you will need to implement your own migration strategy (unless throwing all the data away is fine).

If it is a large amount of data, this mechanism lacks transaction support. So do you write your own? Or use a more appropriate storage mechanism? I strongly encourage a more appropriate storage mechanism such as filesystem of SQLite DB.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCarnalView Question on Stackoverflow
Solution 1 - AndroidChris.DView Answer on Stackoverflow
Solution 2 - Androidישו אוהב אותךView Answer on Stackoverflow
Solution 3 - Androiduser2139213View Answer on Stackoverflow
Solution 4 - AndroidElisha SterngoldView Answer on Stackoverflow
Solution 5 - AndroidShardulView Answer on Stackoverflow
Solution 6 - Androidvladsonkin.comView Answer on Stackoverflow
Solution 7 - AndroidstrayaView Answer on Stackoverflow