How to save Object (includes Array) in Preferences? - android

How to save Object in Preferences which looks like this:
public class ToDoList {
public String name;
public String date;
public ArrayList<Product> products = new ArrayList<Product>();
public boolean isChecked;
}
and then loads its values?

You could do it with serialization. Serialization of an object is a short unique String format of an object that can be serialized. Particularly almost every object can be serialized in java except from the View object. You won't have any problem in your case.
How to do it:
You should make class ToDoList implement Serializable and all classes that are used inside your object, ex Product. String, boolean ArrayList are serializable so you don't have to do anything.
When implementing serialization in an object you have to supply a serial version UID which would be then used to serialize.
So ToDoList would be something like:
public class ToDoList implelements Serializable {
private static final long serialVersionUID = //generate random by eclipse
.....
public ArrayList<Product> products = new ArrayList<Product>();
}
and Product:
public class Product implelements Serializable {
private static final long serialVersionUID = //generate random by eclipse
.....
}
then include this static helper class:
public class ObjectSerializeDeserialize {
public static String ObjectSerialization(Object obj)
{
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
try
{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArray);
objectOutputStream.writeObject(obj);
objectOutputStream.close();
}
catch (Exception e) {
e.printStackTrace();
return "";
}
return new String(Base64.encode(byteArray.toByteArray(), 0));
}
public static Object ObjectDeserialization(String str)
{
byte[] byteArray = Base64.decode(str,0);
Object o;
try
{
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(byteArray));
o = ois.readObject();
ois.close();
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
return o;
}
}
and simply use the following code:
String todolistSer = ObjectSerializeDeserialize.ObjectSerialization(todolistObj);
the above line of code will return an empty String if something goes wrong and will print the detailed message in the log cat.
Then simply save the todolistSer as a String in preferences and reclaim your object like this:
ToDoList todolistObj = (ToDoList) ObjectSerializeDeserialize.ObjectDeserialization(todolistString);
suppress any warnings that are issued by the above method and you are done!
P.S. you can use the above solution whenever you have complicated structures that can not be saved as raw variables and you still don't want to use a database

Preferences are simple key ,value pairs. In your case better use SQLite.

Related

How to deserialize JSON field with dynamic type?

In a request to the Reddit API, there is a field associated with each post called edited. This field either has a boolean value or if a post has been edited, has a long value which I think is the timestamp of when the post was edited. How can I deserialize this with GSON without knowing the type? If I try to deserialize into a Boolean value I get an exception if a timestamp is present.
Image below of JSON response:
Annotating the dynamic field with #JsonAdapter is probably the easiest way to work around this (assuming you have a DTO class):
final class Datum {
#JsonAdapter(MaybeLongTypeAdapter.class)
final Long edited = null;
}
Where MaybeLongTypeAdapter is as follows:
final class MaybeLongTypeAdapter
extends TypeAdapter<Long> {
private MaybeLongTypeAdapter() {
}
#Override
public void write(final JsonWriter out, final Long value) {
throw new UnsupportedOperationException();
}
#Override
public Long read(final JsonReader in)
throws IOException {
switch ( in.peek() ) {
case NULL:
return null;
case BOOLEAN:
if ( in.nextBoolean() ) {
throw new JsonSyntaxException("Unexpected `true` at " + in);
}
return null;
case NUMBER:
return in.nextLong();
default:
throw new JsonSyntaxException("Unexpected element at " + in);
}
}
}
The type adapter above is pretty self-descriptive. It can be implemented in a more generic way, of course, but it's out of scope here. Additionally, please note that it does not pick the original Long type adapter that can be re-configured in GsonBuilder. Example of use:
private static final Gson gson = new Gson();
private static final Type listOfDatumType = new TypeToken<List<Datum>>() {}.getType();
public static void main(final String... args) {
final String json = "[{\"edited\": false},{\"edited\": 1527130582}]";
final List<Datum> data = gson.fromJson(json, listOfDatumType);
for ( final Datum datum : data ) {
System.out.println(datum.edited);
}
}
Output:
null
1527130582

Performance comparison custom class versus arrays

Is it more performant to create a class
public class test {
private Circle c;
private String mac;
private Short abstand;
private Location ort;
public test (String mac, Circle c, Short abstand, Location ort){
this.c = c;
this.mac = mac;
this.abstand = abstand;
this.ort = ort;
}
public String erhalteMac()
{
return mac;
}
//etc.
}
Create an array list by using
ArrayList<test> karte = new ArrayList<test>();
and adding
test t = new test();
t.mac = "...";
karte.add(t);
etc.
to then see if there is an object that has a certain property
public static boolean hM(ArrayList<object> list, String mac) {
for (object object2 : list) {
if (object2.erhalteMac().equals(mac))
{
//work with object2 here.
return true;
}
}
return false;
}
versus simply creating four arrays for each type and iterating through only the mac array in my case and use the index of the matching mac string in each other array to make changes?
The Array method would be a tiny bit faster than the simple List, but
a HashMap would be a lot faster when there are more than a few object instances.

why is the internal file of my android app doubling in size when adding an item to an Arraylist?

Situation: I have an android application. In this android application I have an internal file containing a "User" class (see code below) this user class has an array-list comprised of spendings, of the "Spending" class, comprised of several different basic attributes.
Problem: When I get this user from the internal file, add a "Spending" Object to the array-list of the User, then re-save this user (delete file and recreate) it doubles in size the Spendings array-list.
I even observed it by looking at the files themselves and can see clearly that the entire array-list is doubled every time a spending is added. the user does not seem to be duplicated.
I tried the same process only without adding the spending and it saves just fine without duplication.
the User class:
public class User implements Serializable {
private int id_utilisateur;
private String mail;
private String motDePasse;
private ArrayList<Spending> mySpendings;
public Utilisateur(int id_utilisateur, String mail, String motDePasse) {
this.id_utilisateur = id_utilisateur;
this.mail = mail;
this.motDePasse = motDePasse;
this.mySpendings= new ArrayList<>();
}
//Getters and Setters of all attributes here//
public void addSpending(Spending mySpending) {
mySpendings.add(mySpending);
}
}
My Spending class :
public class Spendingimplements Serializable {
private Integer idSpending;
private Date dateSpending;
private double montant;
private String pieceJoint;
private Magasin magasin;
private String domaine;
private Date garantieDebut;
private Date garantieFin;
private User user;
public Spending(Integer idSpending, Date dateSpending, double montant, User user, String domaine, Magasin magasin, String pieceJoint, Date garantieDebut, Date garantieFin) {
this.idSpending= idSpending;
this.dateSpending= dateSpending;
this.montant = montant;
this.user= user;
this.domaine = domaine;
this.magasin = magasin;
this.pieceJoint = pieceJoint;
this.garantieDebut = garantieDebut;
this.garantieFin = garantieFin;
}
public Spending(Integer idSpending, Date dateSpending, double montant, User user, String domaine, Magasin magasin, String pieceJoint) {
this.idSpending= idSpending;
this.dateSpending= dateSpending;
this.montant = montant;
this.user= user;
this.domaine = domaine;
this.magasin = magasin;
this.pieceJoint = pieceJoint;
this.garantieDebut = null;
this.garantieFin = null;
}
//geters and setters here//
}
My class StorageHelper:
public final class StorageHelper {
public StorageHelper() {}
public static void storeObject(Context context, Object object) {
try {
File dir = context.getFilesDir();
File file = new File(dir, "UserData.data");
file.delete();
FileOutputStream fos = context.openFileOutput("UserData.data", Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(object);
os.close();
fos.close();
} catch (Exception e) {
Log.e("userFile", "Error: Failed to save User into internal storage - \n" + e.toString());
}
}
public static User getUser(Context context) {
User mainUser = null;
try {
FileInputStream fis = context.openFileInput("UserData.data");
ObjectInputStream is = new ObjectInputStream(fis);
mainUser = (User) is.readObject();
is.close();
fis.close();
} catch (Exception e) {
Log.e("userFile", "Error: loading from the internal storage failed - \n" + e.toString());
} finally {
return mainUser;
}
}
}
MainActivity :
StorageHelper storageHelper;
User mainUser = storageHelper.getUser(this.getBaseContext());
mainUser.addSpending(mySpending);
storageHelper.storeObject(this.getBaseContext(), mainUser);

Android save array of custom objects

I have a question about saving an arraylist of custom objects. I have a class called notitie:
public class Notitie implements Serializable{
private String titel = "";
private String type = "";
private String datum = "";
public void setTitel (String titel){
this.titel = titel;
}
public String getTitel(){
return titel;
}
public void setType (String type){
this.type = type;
}
public String getType(){
return type;
}
public void setDatum (String datum){
this.datum = datum;
}
public String getDatum(){
return datum;
}
}
I create some objects of Notitie and add them to my arraylist called notities
ArrayList<Notitie> notities = new ArrayList<Notitie>();
Notitie notitie1 = new Notitie();
notitie1.setTitel("Meting");
notitie1.setType("Watermeting");
notitie1.setDatum("22-09-12");
notities.add(notitie1);
Notitie notitie2 = new Notitie();
notitie1.setTitel("Meting2");
notitie1.setType("Watermeting2");
notitie1.setDatum("23-09-12");
notities.add(notitie2);
Notitie notitie3 = new Notitie();
notitie1.setTitel("Meting3");
notitie1.setType("Watermeting3");
notitie1.setDatum("24-09-12");
notities.add(notitie3);
Now I want to save the filled Arraylist on the device's storage so it can be accessed anytime. I used to save data as a String or some Integers with sharedpreferences but I can't save this Arraylist with that.
Does anybody have a solution?
Thanks in advance!
You do have a few options:
Use serialization, XML or JSON, and store your data in a File. Refer to this solution if you wanna implement serialization.
Store you data using SQLite. Have a look at this tutorial to get started.
EDIT : You might want to read this as well!

java.io.NotSerializableException while writing Serializable object to external storage?

friends,
i am using following code to write Serializable object to external storage.
it throws me error java.io.NotSerializableException
even my object is serializable any one guide me what mistake am i doing?
public class MyClass implements Serializable
{
// other veriable stuff here...
public String title;
public String startTime;
public String endTime;
public boolean classEnabled;
public Context myContext;
public MyClass(Context context,String title, String startTime, boolean enable){
this.title = title;
this.startTime = startTime;
this.classEnabled = enable;
this.myContext = context;
}
public boolean saveObject(MyClass obj) {
final File suspend_f=new File(cacheDir, "test");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
boolean keep = true;
try {
fos = new FileOutputStream(suspend_f);
oos = new ObjectOutputStream(fos);
oos.writeObject(obj); // exception throws here
}
catch (Exception e) {
keep = false;
}
finally {
try {
if (oos != null) oos.close();
if (fos != null) fos.close();
if (keep == false) suspend_f.delete();
}
catch (Exception e) { /* do nothing */ }
}
return keep;
}
}
and calling from activity class to save it
MyClass m= new MyClass(this, "hello", "abc", true);
boolean result =m.saveObject(m);
any help would be appreciated.
This fails due to the Context field in your class. Context objects are not serializable.
Per the Serializable documentation - "When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object."
You can either remove the Context field entirely, or apply the transient attribute to the Context field so that it is not serialized.
public class MyClass implements Serializable
{
...
public transient Context myContext;
...
}

Categories

Resources