Jak serializować obiekt i zapisać go do pliku w systemie Android?

131

Powiedzmy, że mam prostą klasę i po utworzeniu jej jako obiekt chcę móc serializować jej zawartość do pliku i odzyskać ją, ładując ten plik później ... Nie jestem pewien, od czego zacząć, co muszę zrobić, aby serializować ten obiekt do pliku?

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

To chyba najłatwiejsze pytanie na świecie, ponieważ jest to naprawdę proste zadanie w .NET, ale w Androidzie jestem całkiem nowy, więc jestem kompletnie zagubiony.

Ben Lesh
źródło

Odpowiedzi:

251

Zapisywanie (bez kodu obsługi wyjątków):

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

Ładowanie (bez kodu obsługi wyjątków):

FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
SimpleClass simpleClass = (SimpleClass) is.readObject();
is.close();
fis.close();
Ralkie
źródło
Bardzo przydatne. Czy mógłbyś wyjaśnić, czy musimy serializować klasę do zapisu jako plik obiektowy.
Arun Chettoor
4
Ta funkcja jest niejawnie dodawana do Twojej klasy, jeśli używasz interfejsu Serializable. Jeśli wszystko, czego chcesz, to prosta serializacja obiektów, to właśnie bym użył. Jest również niezwykle łatwy do wdrożenia.developer.android.com/reference/java/io/Serializable.html
mtmurdock
6
+1, Do zapisywania wielu obiektów wymagana jest sztuczka: stackoverflow.com/a/1195078/1321401
Luten
2
Czy powinno być również wywołanie funkcji fos.close () i fis.close ()?
IcedDante
Poleciłbym Paper . Używa serializacji Kryo i znacznie szybszej niż zwykła serializacja Java.
Oleksii Masnyi
36

Wypróbowałem te 2 opcje (odczyt / zapis), ze zwykłymi obiektami, tablicą obiektów (150 obiektów), mapą:

Opcja 1:

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

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

Opcja 2 jest dwukrotnie szybsza niż opcja 1

Niedogodność opcji 2 polega na tym, że musisz utworzyć określony kod do odczytu:

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
źródło
3
Dlaczego powiedziałbyś, że opcja 2 jest szybsza? Być może dlatego, że SharedPreferences jest przechowywany w pamięci, a zmierzony czas nie obejmował zapisania go w systemie plików? Pytam o to, ponieważ wyobrażam sobie, że serializacja do strumienia obiektów musi być bardziej wydajna niż do ciągu JSON.
CesarPim
10

Właśnie utworzyłem klasę do obsługi tego za pomocą Generics, więc może być używana ze wszystkimi typami obiektów, które można serializować:

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
źródło
7

Kompletny kod z obsługą błędów i dodanym strumieniem plików zostaje zamknięty. Dodaj go do swojej klasy, którą chcesz serializować i deserializować. W moim przypadku nazwa klasy to CreateResumeForm. Powinieneś zmienić to na własną nazwę klasy. Androidinterfejs Serializablenie wystarcza do zapisania obiektów do pliku, tworzy tylko strumienie.

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

Użyj go w ten sposób w Activity:

form = CreateResumeForm.readFromFile(this);
Denis Kutlubaev
źródło
0

Używam 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
źródło
0

Musisz dodać klasę ObjectSerialization do swojego programu, co może działać

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

}

jeśli używasz do przechowywania tablicy z SharedPreferences niż użyj następujących: -

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

Aby serializować: -

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

Aby deserializować: -

newarray = (CAST_IT_TO_PROPER_TYPE) ObjectSerializer.deSerialize(sharedPreferences.getString(name),null);
Priyanshu Dubey
źródło