2017-11-05 3 views
0

나는 안드로이드에 있는데 객체의 목록을 파일에 저장하려고하는데 항상 예외가 발생한다. java.io.NotSerializableException : android.app.Application.Serializable 객체를 파일에 쓰려고 할 때

나는이 문제를 일으킬 수있는 것을 찾기 위해 노력했지만 내가 찾은 모든이 오류가 Context 객체를 직렬화하려고 할 때 발생합니다 있다는 것입니다하지만 난 응용 프로그램 또는 컨텍스트에 관련된 아무것도 직렬화하는 것을 시도하고 있지 않다 .

DataFileManager.java

public class DataFileManager implements Serializable { 
    public static final String FILE_NAME = "circles.dat"; 
    private transient final Context ctxt; 
    private Set<Save> saves; 
    public DataFileManager(Context ctxt) { 
     this.ctxt = ctxt; 
     this.saves = new HashSet<>(); 
     reloadSaves(); 
    } 

    public void reloadSaves() { 
     File file = file(); 
     if(file.exists()) { 
      try (ObjectInputStream reader = new ObjectInputStream(
        new BufferedInputStream(ctxt.openFileInput(FILE_NAME)))) { 
       saves.clear(); 
       try { 
        while (true) { 
         Save save = (Save) reader.readObject(); 
         saves.add(save); 
        } 
       } catch(EOFException e) { 
       } finally { 
        reader.close(); 
       } 
      } catch (IOException | ClassNotFoundException e) { 
       Log.e(e.getClass().getName(), "", e); 
      } 
     } else 
      Log.e("load", "file does not exist"); 
    } 

    private void save() { 
     try { 
      file().createNewFile(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      Log.e(e.getClass().getName(), "", e); 
     } 
     try (ObjectOutputStream writer = new ObjectOutputStream(new BufferedOutputStream(ctxt.openFileOutput(FILE_NAME, Context.MODE_PRIVATE)))) { 
      Iterator<Save> iter = saves.iterator(); 
      while(iter.hasNext()) { 
       Save save = iter.next(); 
       writer.writeObject(save); 
      } 
      writer.flush(); 
      writer.close(); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
      Log.e(e.getClass().getName(), "", e); 
     } catch (IOException e) { 
      Log.e(e.getClass().getName(), "", e); 
     } 
    } 


    private File file() { 
     return ctxt.getFileStreamPath(FILE_NAME); 
    } 


    public Save save(String saveName, Set<Circle> circles) throws SaveAlreadyExistsException { 
     if(exists(saveName)) 
      throw new SaveAlreadyExistsException(); 
     Save save = createSave(saveName, circles); 
     if(!saves.add(save)) 
      throw new SaveAlreadyExistsException(); 
     return save; 
    } 

    public Save forceSave(String saveName, Set<Circle> circles) throws UnknownSaveException { 
     Save save; 
     if(exists(saveName)) 
      (save = find(saveName)).overwrite(circles); 
     else { 
      save = createSave(saveName, circles); 
      if(!saves.add(save)) { 
       saves.remove(save); 
       if(!saves.add(save)) 
        throw new UnknownSaveException("Couldn't add Save object to the list"); 
      } 
      save(); 
     } 
     return save; 
    } 

    private Save createSave(String name, Set<Circle> circles) { 
     Save save = new Save(name); 
     save.circles.addAll(circles); 
     return save; 
    } 

    public boolean exists(String saveName) { 
     return saves.stream().anyMatch(s -> s.getName().equals(saveName)); 
    } 

    public boolean existsIgnoreCase(String saveName) { 
     return saves.stream().anyMatch(s -> s.getName().equalsIgnoreCase(saveName)); 
    } 

    public Save find(String saveName) { 
     return saves.stream().filter(s -> s.getName().equals(saveName)).findFirst().orElse(null); 
    } 

    public List<Save> search(String query) { 
     return saves.stream().filter(s -> s.getName().toLowerCase().contains(query.toLowerCase())) 
        .collect(Collectors.toList()); 
    } 

    public Set<Save> getSaves() { 
     return Collections.unmodifiableSet(saves); 
    } 



    public class Save implements Serializable { 
     private final String  name; 
     private final Set<Circle> circles; 

     private Save(String name) { 
      this.name = name; 
      circles = new HashSet<>(); 
     } 

     public boolean overwrite(Set<Circle> circles) { 
      if (circles != null && circles.size() > 0) { 
       this.circles.clear(); 
       this.circles.addAll(circles); 
       save(); 
       return true; 
      } 
      return false; 
     } 

     public Set<Circle> getCircles() { 
      return circles.stream().map(Circle::clone).collect(Collectors.toSet()); 
     } 

     public String getName() { 
      return name; 
     } 

     @Override 
     public boolean equals(Object obj) { 
      return obj != null && obj instanceof Save && ((Save)obj).name.equals(this.name); 
     } 
    } 

    public static class SaveAlreadyExistsException extends UnknownSaveException { 
     public SaveAlreadyExistsException() { 
      super("save already exists"); 
     } 
    } 

    public static class UnknownSaveException extends Exception { 
     private static final String DFLT_MSG = "An unknown error occured"; 

     public UnknownSaveException() { 
      super(DFLT_MSG); 
     } 

     public UnknownSaveException(String message) { 
      super(message); 
     } 

     public UnknownSaveException(String message, Throwable cause) { 
      super(message, cause); 
     } 

     public UnknownSaveException(Throwable cause) { 
      super(DFLT_MSG, cause); 
     } 
    } 
} 

Circle.java

public class Circle implements Cloneable, Serializable { 
    private static long nextID = 0; 
    private float radius, centerX, centerY; 
    private final long id; 

    public Circle(float centerX, float centerY) { 
     this(centerX, centerY, nextID++); 
    } 

    private Circle(float centerX, float centerY, long id) { 
     this.radius = 0; 
     this.centerX = centerX; 
     this.centerY = centerY; 
     this.id = id; 
    } 

    public float getRadius() { 
     return radius; 
    } 

    public void setRadius(float radius) { 
     this.radius = radius; 
    } 

    public float getCenterX() { 
     return centerX; 
    } 

    public void setCenterX(float centerX) { 
     this.centerX = centerX; 
    } 

    public float getCenterY() { 
     return centerY; 
    } 

    public void setCenterY(float centerY) { 
     this.centerY = centerY; 
    } 

    @Override public Circle clone() { 
     return new Circle(getCenterX(), getCenterY(), id); 
    } 

    public boolean isCloneOf(Circle circle) { 
     return circle != null && circle != this && this.id == circle.id; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return obj != null && obj instanceof Circle && !isCloneOf((Circle)obj); 
    } 
} 

스택 트레이스

E/java.io.NotSerializableException : java.io.NotSerializableException : android.app.Application at java.io.ObjectOutputStream.writeObject0 (ObjectOutputStream.java:1224) java.io.ObjectOutputStream.writeOrdinaryObject (ObjectOutputStream.java:1472)에서 java.io.ObjectOutputStream.writeSerialData (ObjectOutputStream.java:1549) at java.io.ObjectOutputStream.writeOrdinaryObject (ObjectOutputStream.java:1472) 에서 자바 .io.ObjectOutputStream.writeObject0 (ObjectOutputStream.java:1218) at java.io.ObjectOutputStream.defaultWriteFields (ObjectOutputStream.java:1584) at java.io.ObjectOutputStream.writeSerialData (ObjectOutputStream.java:1549) at java.io .ObjectOutputStream.writeOrdinaryObject (ObjectOutputStream.java:1472) at java.io.ObjectOutputStream.writeObject0 (ObjectOutputStream.java:1218) at java.io.ObjectOutputStream.writeObject (ObjectOutputStream.java:346) at com.multimedia.tp3 어. 오. del.files.DataFileManager.save (DataFileManager.java:77) at com.multimedia.tp3.model.files.DataFileManager.forceSave (DataFileManager.java:116) at com.multimedia.tp3.DrawSurface.save (DrawSurface. 자바 : com.multimedia.tp3.MainActivity.onActivityResult (MainActivity.java:95) android.app.ActivityThread.deliverResults에서 android.app.Activity.dispatchActivityResult (Activity.java:6996) 에서 (ActivityThread 131) . 자바 : 4069) android.app.ActivityThread.handleSendResult (ActivityThread.java:4116에서 ) android.app.ActivityThread.-wrap20 android.app.ActivityThread $ H.handleMessage에서 (ActivityThread.java) 에서 (ActivityThread.java : 1516) android.os.Handler.dispatchMessage (Handler.java:102) 에서 droid.os.Looper.loop (Looper.java:159) android.app.ActivityThread.main (ActivityThread.java:6097) at java.lang.reflect.Method.invoke (기본 메소드) 에서 com.android .internal.os.ZygoteInit $ MethodAndArgsCaller.run com.android.internal.os.ZygoteInit.main (ZygoteInit.java:755)에서 (ZygoteInit.java:865) 는

+0

'Circle'은 독립 실행 형 Java 클래스입니까, 아니면 다른 클래스의 내부 클래스입니까? – CommonsWare

+0

@CommonsWare'Circle'은'DataFileManager'의 내부 클래스입니다 – DrunkenPoney

+0

당신은 어딘가에서 내부 클래스를 직렬화하고 있습니다. 'file(). createNewFile();'는 여기서는 무의미하며 예외를 던지지 않습니다. 세트를 반복 할 필요가 없습니다. 모든 것을 한 번에 저장할 수 있습니다. – EJP

답변

2

그것의 내부 클래스입니다 DataFileManager

public class 대신 public static class이되도록하십시오.지금은 Circle에 외부 참조 인스턴스를 생성 한 암시 적 참조가 있으므로 직렬화되는 DataFileManager에서 일련 번호가 질식합니다.

+0

나는 아직도'NotSerializableException'을 얻었지만 지금은 정말 처음에는 저장하려고 시도 할 때만 던져 버리고, 저장하려고하는 객체는 부분적으로 저장된다. (첫 번째 시도뿐만 아니라). 서클의 위치 만 저장되지만 반경은 저장되지 않습니다. – DrunkenPoney

+1

@DrunkenPoney : 나는 당신을 정말로 도울 수 없다. 새 스택 추적을 포함하여 새로운 [mcve]를 사용하여 별도의 질문을하는 것이 좋습니다. 또는 Java serialization을 사용하지 않는 것이 좋습니다. JSON, XML 또는 SQLite를 사용하여 데이터를 지속 할 수 있습니다. – CommonsWare

+0

좋아요. JSON 또는 XML을 사용하려고합니다. 스택 추적에 똑같은 스택 추적을 사용하고 있습니다. 디버그 콘솔이 던져 질 때 앱에서 디버거 콘솔 연결을 끊을 때만 나타납니다. – DrunkenPoney