ObjectInputStream.readObject() NotSerializableException

У меня есть некоторые проблемы с сохранением и чтением объектов, сохраненных в файле с помощью ObjectOutputStream и ObjectInputStream в моем приложении для Android. У меня есть два класса Workout и Exercise, Workout содержит среди прочего список упражнений. Оба класса реализуют Serializable. Вот фактический код:

Тренировка

package com.mycompany.myapp;

public class Workout implements Serializable{

private String _name;
protected ArrayList<Exercise> _list = new ArrayList<Exercise>();
private static final long serialVersionUID = 1L;
private File _fileSave;
final Context context = MyApp.getContext();

Workout(){
    _name = "Empty";
    _list = null;
 }

 Workout(String n, ArrayList<Exercise> e){
     _name = n;
     _list.addAll(e);
 }

 Workout(File fs){
     ObjectInputStream ois;
     _fileSave = fs;
     try{
         ois = new ObjectInputStream(new FileInputStream(fs));
         Workout n = (Workout) ois.readObject();   //here it fails and throws the exception
         ois.close();
         _name = n._name;
         _list = n._list;
     }catch(IOException e){ 
        e.getCause();
     }catch(ClassNotFoundException e) {
     }
 }

 protected void save(){                                 
    ObjectOutputStream oos;
    _fileSave = new File(context.getFilesDir(), _name + ".w");
    try{
        oos = new ObjectOutputStream(new FileOutputStream(_fileSave));
        oos.writeObject(this);
        oos.close();
    }
    catch(Exception e){
        e.getCause();
    }
 }
 ...

Упражнение

public class Exercise implements Serializable{

protected String _name;
protected int _weight;
protected int _reps;
protected int _sets;
protected int _pause;
protected int _duration;
private static final long serialVersionUID = 1L;

Exercise(){
    _name = "New Empty Exercise";
    _weight = 0;
    _reps = 0;
    _sets = 0;
    _pause = 0;
}

Exercise(String n, int w, int r, int s, int d, int p){
    _name = n;
    _weight = w;
    _reps = r;
    _sets = s;
    _duration = d;
    _pause = p;
}

}

У меня нет проблем с сохранением текущего экземпляра класса, но когда я пытаюсь прочитать объект, возникает исключение NotSerializableException. Вот подробности и бэктрек:

cause = java.io.NotSerializableException: com.mycompany.myapp.MyApp

backtrace = { long[44]@b77201, class java.io.ObjectInputStream, class java.io.ObjectInputStream, class java.io.ObjectInputStream, class java.io.ObjectInputStream, class java.io.ObjectInputStream, class java.io.ObjectInputStream, class com.mycompany.myapp.Workout$0$debug, class com.mycompany.myapp.Workout, class com.mycompany.myapp.Menu$0$debug, class com.mycompany.myapp.Menu, class android.app.Activity, class android.app.Instrumentation, class android.app.ActivityThread, class android.app.ActivityThread, class android.app.ActivityThread, class android.app.ActivityThread$H, class android.os.Handler, class android.os.Looper, class android.app.ActivityThread, class java.lang.reflect.Method, class com.android.internal.os.Zygote$MethodAndArgsCaller, class com.android.internal.os.ZygoteInit }

Я не могу понять, в чем моя ошибка или что мне не хватает. Заранее спасибо за вашу помощь!


person Sba    schedule 01.12.2017    source источник
comment
Контекст не может быть сериализован. Сделайте его преходящим. transient final Context context = MyApp.getContext();   -  person Bedla    schedule 01.12.2017
comment
Вы также должны получить такое же исключение при сериализации. Не игнорируйте исключения.   -  person user207421    schedule 12.03.2021


Ответы (1)


Чтобы объект был сериализуемым, все его поля экземпляра должны быть сериализуемыми, а также все его поля экземпляра и т. д. Ваш Workout имеет,

final Context context = MyApp.getContext();

Объект Android Context не сериализуем. В вашем случае, поскольку вы, по-видимому, просто сохраняете контекст в статическом поле, просто удалите для него поле экземпляра и используйте MyApp.getContent() непосредственно там, где вам это нужно. Не то чтобы я оправдывал использование глобальных переменных.

Или, как указал @Bedla в комментариях,

transient final Context context = MyApp.getContext();

В качестве альтернативы вы можете пометить поле transient, чтобы обозначить, что оно не должно сериализоваться. Но, конечно, вы должны быть подготовлены к тому, что это поле не будет десериализовано.

person Jeffrey Blattman    schedule 01.12.2017