Use parcelable to store item as sharedpreferences?
Asked Answered
J

6

32

I have a couple objects, Location, in my app stored in an ArrayList and use parcelable to move these between activities. The code for the object looks like this:

public class Location implements Parcelable{

private double latitude, longitude;
private int sensors = 1;
private boolean day;
private int cloudiness;

/*
Måste ha samma ordning som writeToParcel för att kunna återskapa objektet.
 */
public Location(Parcel in){
    this.latitude = in.readDouble();
    this.longitude = in.readDouble();
    this.sensors = in.readInt();
}

public Location(double latitude, double longitude){
    super();
    this.latitude = latitude;
    this.longitude = longitude;
}

public void addSensors(){
    sensors++;
}


public void addSensors(int i){
    sensors = sensors + i;
}

+ Some getters and setters.

Now I am in need of storing these objects more permanently. I read somewhere that I can serialize the objects and save as sharedPreferences. Do I have to implement serializeable aswell or can I do something similar with parcelable?

Joey answered 10/2, 2015 at 18:24 Comment(0)
N
41

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.

Noteworthy answered 10/2, 2015 at 18:33 Comment(2)
Ah! In that case I suppose I'll just have to serialize it instead.Joey
@Joey Relevant: #5418660Concinnous
C
77

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.

Cline answered 8/9, 2016 at 8:18 Comment(1)
Somehow Gson().toJson(location) is not working as expected, it is just giving back empty braces like {} while location is there. Saving best location Location[gps 37.343339,-122.097152 hAcc=1.7821856 et=+1m54s707ms alt=46.24608612060547 vel=0.6257401 mock] string>> {}Brooch
N
41

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.

Noteworthy answered 10/2, 2015 at 18:33 Comment(2)
Ah! In that case I suppose I'll just have to serialize it instead.Joey
@Joey Relevant: #5418660Concinnous
C
3

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 :)

Custodian answered 5/6, 2021 at 13:44 Comment(1)
See gist: gist.github.com/ArnyminerZ/580ca9e9c404a172e583b922d453ca78Custodian
S
2

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")
Stellastellar answered 22/9, 2021 at 6:55 Comment(0)
C
0

You can create class both Gson'able and Parcelable like

@Parcelize
data class ApiRate(
    @SerializedName("tp") val tp: Int,
    @SerializedName("name") val name: String,
    @SerializedName("from") val from: Int,
    @SerializedName("currMnemFrom") val currMnemFrom: String,
    @SerializedName("to") val to: Int,
    @SerializedName("currMnemTo") val currMnemTo: String,
    @SerializedName("basic") val basic: String,
    @SerializedName("buy") val buy: String,
    @SerializedName("sale") val sale: String,
    @SerializedName("deltaBuy") val deltaBuy: String,
    @SerializedName("deltaSell") val deltaSell: String
) : Parcelable

Possible.

Como answered 24/6, 2021 at 8:32 Comment(0)
S
-5

The preferred way would be to implement an IntentService probably

Surrender answered 1/4, 2020 at 17:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.