Wie serialisiere ich ein Objekt und speichere es in einer Datei in Android?

128

Angenommen, ich habe eine einfache Klasse, und sobald sie als Objekt instanziiert ist, möchte ich in der Lage sein, ihren Inhalt in eine Datei zu serialisieren und sie abzurufen, indem ich diese Datei zu einem späteren Zeitpunkt lade. Ich bin mir nicht sicher, wo ich hier anfangen soll. Was muss ich tun, um dieses Objekt in eine Datei zu serialisieren?

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? */
   }
}

Dies ist wahrscheinlich die einfachste Frage der Welt, da dies in .NET eine wirklich einfache Aufgabe ist, aber in Android bin ich ziemlich neu und daher völlig verloren.

Ben Lesh
quelle

Antworten:

250

Speichern (ohne Ausnahmebehandlungscode):

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

Laden (ohne Ausnahmebehandlungscode):

FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
SimpleClass simpleClass = (SimpleClass) is.readObject();
is.close();
fis.close();
Ralkie
quelle
Sehr hilfreich. Könnten Sie bitte erklären, ob wir die Klasse zum Schreiben als Objektdatei serialisieren müssen.
Arun Chettoor
4
Diese Funktionalität wird Ihrer Klasse implizit hinzugefügt, wenn Sie die serialisierbare Schnittstelle verwenden. Wenn Sie nur eine einfache Objektserialisierung wünschen, würde ich diese verwenden. Es ist auch sehr einfach zu implementieren. developer.android.com/reference/java/io/Serializable.html
mtmurdock
6
+1, Für das Speichern mehrerer Objekte ist ein Trick erforderlich: stackoverflow.com/a/1195078/1321401
Luten
2
Sollte es auch einen Aufruf von fos.close () und fis.close () geben?
IcedDante
Ich würde Paper empfehlen . Es verwendet die Kryo-Serialisierung und ist viel schneller als die übliche Java-Serialisierung.
Aleksey Masny
36

Ich habe diese 2 Optionen (Lesen / Schreiben) mit einfachen Objekten, Array von Objekten (150 Objekte), Map ausprobiert:

Option 1:

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

Option 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();

Option 2 ist zweimal schneller als Option 1

Die Unannehmlichkeit von Option 2 besteht darin, dass Sie einen bestimmten Code zum Lesen erstellen müssen:

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);
surfealokesea
quelle
3
Warum ist Option 2 Ihrer Meinung nach schneller? Vielleicht, weil SharedPreferences im Speicher bleibt und die von Ihnen gemessene Zeit das Speichern im Dateisystem nicht beinhaltete? Ich frage dies, weil ich mir vorstellen würde, dass die Serialisierung in einen Objektstrom effizienter sein muss als in einen JSON-String.
CesarPim
10

Ich habe gerade eine Klasse erstellt, um dies mit Generics zu handhaben, damit sie mit allen Objekttypen verwendet werden kann, die serialisierbar sind:

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);
    }

}
Sandro Machado
quelle
7

Vollständiger Code mit Fehlerbehandlung und hinzugefügtem Dateistream wird geschlossen. Fügen Sie es Ihrer Klasse hinzu, die Sie serialisieren und deserialisieren möchten. In meinem Fall ist der Klassenname CreateResumeForm. Sie sollten es in Ihren eigenen Klassennamen ändern. AndroidDie Schnittstelle Serializablereicht nicht aus, um Ihre Objekte in der Datei zu speichern, sondern erstellt nur Streams.

// 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;
}

Verwenden Sie es so in Ihrem Activity:

form = CreateResumeForm.readFromFile(this);
Denis Kutlubaev
quelle
0

Ich benutze 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());
}
}
Zod
quelle
0

Sie müssen Ihrem Programm eine ObjectSerialization-Klasse hinzufügen. Folgendes kann funktionieren

    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;
}

}}

Wenn Sie ein Array mit SharedPreferences speichern, verwenden Sie Folgendes: -

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

So serialisieren Sie: -

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

Deserialisieren: -

newarray = (CAST_IT_TO_PROPER_TYPE) ObjectSerializer.deSerialize(sharedPreferences.getString(name),null);
Priyanshu Dubey
quelle