Use parcelable to store item as sharedpreferences?

Since parcelable doesn't help to place your data in persistent storage (see StenSoft's answer), you can use gson to persist your Location instead:

Saving a Location:

val json = Gson().toJson(location)
sharedPreferences.edit().putString("location", json).apply()

Retrieving a Location:

val json = sharedPreferences.getString("location", null)
return Gson().fromJson(json, Location::class.java)

In case you're still using Java, replace val with String, Gson() with new Gson(), ::class.java with .class and end each line with a semicolumn.


From documentation of Parcel:

Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.


Since Parcel should not be used to be stored in the Shared Preferences, an alternative could be to use the new Kotlin Serialization.

Here are two extension functions that add serializable to the Shared Preferences:

inline fun <reified S> SharedPreferences.getSerializable(key: String): S? {
    return getString(key, null)?.let {
        Json.decodeFromString(it) as? S
    }
}

inline fun <reified S> SharedPreferences.putSerializable(key: String, value: S) {
    val jsonString = Json.encodeToString(value)
    edit().putString(key, jsonString).apply()
}

which then can be used like this:

@Serializable
data class Location {
  val double latitude,
  val double longitude
}

val sharedPrefs = context.getSharedPreferences("mySharePrefs", Context.MODE_PRIVATE)
val location = Location(1.1, 2.2)
sharedPrefs.putSerializable("location", location)
val locationFromSharedPrefs = sharedPrefs.getSerializable<Location>("location")

If you are using Kotlin, I would take the approach of Cristan, but with some extension functions, see:

import android.content.SharedPreferences
import android.os.Parcelable
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException

fun SharedPreferences.Editor.putParcelable(key: String, parcelable: Parcelable) {
    val json = Gson().toJson(parcelable)
    putString(key, json)
}

inline fun <reified T : Parcelable?> SharedPreferences.getParcelable(key: String, default: T): T {
    val json = getString(key, null)
    return try {
        if (json != null)
            Gson().fromJson(json, T::class.java)
        else default
    } catch (_: JsonSyntaxException) {
        default
    }
}

And then you could use it as follows, for storing:

sharedPreferences.edit {
    putParcelable("location", location)
}

And for reading:

val location = sharedPreferences.getParcelable<Location?>("location", null)

This is a pretty clean way of using the Cristan proposal. Hope it works for you :)