Come posso serializzare un oggetto e salvarlo su un file in Android?


128

Supponiamo di avere una classe semplice e, una volta istanziato come oggetto, voglio poter serializzare il suo contenuto su un file e recuperarlo caricando quel file in un secondo momento ... Non sono sicuro da dove iniziare qui, cosa devo fare per serializzare questo oggetto in un file?

public class SimpleClass {
   public string name;
   public int id;
   public void save() {
       /* wtf do I do here? */
   }
   public static SimpleClass load(String file) {
       /* what about here? */
   }
}

Questa è probabilmente la domanda più semplice al mondo, perché si tratta di un'attività davvero semplice in .NET, ma in Android sono abbastanza nuovo, quindi mi sono completamente perso.

Risposte:


250

Salvataggio (senza codice di gestione delle eccezioni):

FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.close();
fos.close();

Caricamento (senza codice di gestione delle eccezioni):

FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
SimpleClass simpleClass = (SimpleClass) is.readObject();
is.close();
fis.close();

Molto utile. Potresti spiegare se è necessario serializzare la classe per la scrittura come file oggetto.
Arun Chettoor,

4
Questa funzionalità viene implicitamente aggiunta alla tua classe se usi l'interfaccia Serializable. Se tutto ciò che desideri è una semplice serializzazione di oggetti, è quello che userei. È anche estremamente facile da implementare. developer.android.com/reference/java/io/Serializable.html
mtmurdock

6
+1, Per il salvataggio di più oggetti è necessario un trucco: stackoverflow.com/a/1195078/1321401
Luten

2
Dovrebbe esserci anche una chiamata a fos.close () e fis.close ()?
IcedDante,

Consiglierei Paper . Utilizza la serializzazione di Kryo e una serializzazione Java molto più veloce della comune.
Aleksey Masny,

36

Ho provato queste 2 opzioni (lettura / scrittura), con oggetti semplici, array di oggetti (150 oggetti), Mappa:

Opzione 1:

FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.close();

Opzione 2:

SharedPreferences mPrefs=app.getSharedPreferences(app.getApplicationInfo().name, Context.MODE_PRIVATE);
SharedPreferences.Editor ed=mPrefs.edit();
Gson gson = new Gson(); 
ed.putString("myObjectKey", gson.toJson(objectToSave));
ed.commit();

L'opzione 2 è due volte più rapida dell'opzione 1

L'inconveniente dell'opzione 2 è che devi creare un codice specifico per la lettura:

Gson gson = new Gson();
JsonParser parser=new JsonParser();
//object arr example
JsonArray arr=parser.parse(mPrefs.getString("myArrKey", null)).getAsJsonArray();
events=new Event[arr.size()];
int i=0;
for (JsonElement jsonElement : arr)
    events[i++]=gson.fromJson(jsonElement, Event.class);
//Object example
pagination=gson.fromJson(parser.parse(jsonPagination).getAsJsonObject(), Pagination.class);

3
Perché diresti che l'opzione 2 è più veloce? Forse perché SharedPreferences è tenuto in memoria e il tempo che hai misurato non ha incluso il salvataggio nel file system? Lo chiedo perché immagino che la serializzazione su un flusso di oggetti debba essere più efficiente di una stringa JSON.
CesarPim

10

Ho appena creato una classe per gestirlo con Generics, quindi può essere utilizzato con tutti i tipi di oggetti serializzabili:

public class SerializableManager {

    /**
     * Saves a serializable object.
     *
     * @param context The application context.
     * @param objectToSave The object to save.
     * @param fileName The name of the file.
     * @param <T> The type of the object.
     */

    public static <T extends Serializable> void saveSerializable(Context context, T objectToSave, String fileName) {
        try {
            FileOutputStream fileOutputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

            objectOutputStream.writeObject(objectToSave);

            objectOutputStream.close();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Loads a serializable object.
     *
     * @param context The application context.
     * @param fileName The filename.
     * @param <T> The object type.
     *
     * @return the serializable object.
     */

    public static<T extends Serializable> T readSerializable(Context context, String fileName) {
        T objectToReturn = null;

        try {
            FileInputStream fileInputStream = context.openFileInput(fileName);
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            objectToReturn = (T) objectInputStream.readObject();

            objectInputStream.close();
            fileInputStream.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        return objectToReturn;
    }

    /**
     * Removes a specified file.
     *
     * @param context The application context.
     * @param filename The name of the file.
     */

    public static void removeSerializable(Context context, String filename) {
        context.deleteFile(filename);
    }

}

7

Codice completo con gestione degli errori e flusso di file aggiunto chiuso. Aggiungilo alla tua classe che desideri poter serializzare e deserializzare. Nel mio caso il nome della classe è CreateResumeForm. Dovresti cambiarlo con il tuo nome di classe. Androidl'interfaccia Serializablenon è sufficiente per salvare i tuoi oggetti nel file, crea solo flussi.

// Constant with a file name
public static String fileName = "createResumeForm.ser";

// Serializes an object and saves it to a file
public void saveToFile(Context context) {
    try {
        FileOutputStream fileOutputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(this);
        objectOutputStream.close();
        fileOutputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}


// Creates an object by reading it from a file
public static CreateResumeForm readFromFile(Context context) {
    CreateResumeForm createResumeForm = null;
    try {
        FileInputStream fileInputStream = context.openFileInput(fileName);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        createResumeForm = (CreateResumeForm) objectInputStream.readObject();
        objectInputStream.close();
        fileInputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return createResumeForm;
}

Usalo così nel tuo Activity:

form = CreateResumeForm.readFromFile(this);

0

Uso SharePrefrences:

package myapps.serializedemo;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.io.IOException;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

//Create the SharedPreferences
    SharedPreferences sharedPreferences = this.getSharedPreferences("myapps.serilizerdemo", Context.MODE_PRIVATE);
    ArrayList<String> friends = new ArrayList<>();
    friends.add("Jack");
    friends.add("Joe");
    try {

 //Write / Serialize
 sharedPreferences.edit().putString("friends",
    ObjectSerializer.serialize(friends)).apply();
    } catch (IOException e) {
        e.printStackTrace();
    }
//READ BACK
    ArrayList<String> newFriends = new ArrayList<>();
    try {
        newFriends = (ArrayList<String>) ObjectSerializer.deserialize(
                sharedPreferences.getString("friends", ObjectSerializer.serialize(new ArrayList<String>())));
    } catch (IOException e) {
        e.printStackTrace();
    }
    Log.i("***NewFriends", newFriends.toString());
}
}

0

È necessario aggiungere una classe ObjectSerialization al programma potrebbe funzionare quanto segue

    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 ObjectSerializer {

public static String serialize(Serializable obj) throws IOException {
    if (obj == null) return "";
    try {
        ByteArrayOutputStream serialObj = new ByteArrayOutputStream();
        ObjectOutputStream objStream = new ObjectOutputStream(serialObj);
        objStream.writeObject(obj);
        objStream.close();
        return encodeBytes(serialObj.toByteArray());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

public static Object deserialize(String str) throws IOException {
    if (str == null || str.length() == 0) return null;
    try {
        ByteArrayInputStream serialObj = new ByteArrayInputStream(decodeBytes(str));
        ObjectInputStream objStream = new ObjectInputStream(serialObj);
        return objStream.readObject();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

public static String encodeBytes(byte[] bytes) {
    StringBuffer strBuf = new StringBuffer();

    for (int i = 0; i < bytes.length; i++) {
        strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
        strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
    }

    return strBuf.toString();
}

public static byte[] decodeBytes(String str) {
    byte[] bytes = new byte[str.length() / 2];
    for (int i = 0; i < str.length(); i+=2) {
        char c = str.charAt(i);
        bytes[i/2] = (byte) ((c - 'a') << 4);
        c = str.charAt(i+1);
        bytes[i/2] += (c - 'a');
    }
    return bytes;
}

}

se si utilizza per archiviare un array con SharedPreferences, utilizzare quanto segue: -

SharedPreferences sharedPreferences = this.getSharedPreferences(getPackageName(),MODE_PRIVATE);

Serializzare: -

sharedPreferences.putString("name",ObjectSerializer.serialize(array));

Per deserializzare: -

newarray = (CAST_IT_TO_PROPER_TYPE) ObjectSerializer.deSerialize(sharedPreferences.getString(name),null);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.