2016-04-08 10 views
1

を書き込み中:にStackOverflowError私はのは、彼らがこれらのように見えると仮定しましょう、2つのクラスを持っているParcelable

Movie.java

public class Movie implements Parcelable { 
    private int year; 
    private List<Actor> actors; 

    // Constructor, getters and setters, Parcelable implementation 
} 

Actor.java

public class Actor implements Parcelable { 
    private String name; 
    private Movie movie; 

    // Constructor, getters and setters, Parcelable implementation 
} 

そして今、私がしようとしています私はStackableflowErrorを取得することができます:

java.lang.StackOverflowError 
    at java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1012) 
    at java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1535) 
    at java.lang.ClassLoader.getClassLoadingLock(ClassLoader.java:463) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:404) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 
    at android.os.Parcel.writeParcelable(Parcel.java) 
    atcom.example.android.data.model.Actor.writeToParcel(Actor.java:58) 
    at android.os.Parcel.writeTypedList(Parcel.java:1106) 
    at com.example.android.data.model.Movie.writeToParcel(Movie.java:70) 

ここではネストされたクラスに問題があることを理解しています。これは、Movieをパーセルに書き込もうとするとActorを書き込もうとしますが、ActorではMovieを書き込もうとするからです。入れ子になったクラスの問題を回避するための方法

QUESTION

+0

完全なエラーログを投稿 –

+0

2行追加、残りは同じです。 – ThirdMartian

+0

これは役に立つかもしれないhttp://stackoverflow.com/a/18177327/1320616 –

答えて

0

MovieActorの内部に保存しないでください。それらの間の双方向の関係は、エラーを作成しています。

また、ActorにはMovieを格納する必要はありません。実際の人生の俳優は、多くの映画に出演することも、映画に出演することも、何の役にも立たないこともあります。

+0

来る、それはhypotheticです。私はそれがエラーを作成していることを知って、私はそれについて書いた。どのようにそのようなモデル構造に対処するのですか? – ThirdMartian

+0

これは親子関係です。それを行う最善の方法は、逆ではなく、親にのみ子を格納することです。 – 4castle

0

代わりにExternalizableを実装してください。次に、writeObjectを使用して、オブジェクトIDのアカウントで参照をシリアル化します。

Javaシリアル化プロトコルは、オブジェクト間の循環相互依存性を処理するように設計されています。パーセルラブルは設計上のものをサポートしていません。そのようなサポートをハックしようとすると、すでに作成者が行っている作業が無駄に繰り返されます。とObjectOutputStreamです。注:私はSerializableを実装することを提案していないことに注意してください。これは、リフレクションベースなので遅くなりますが、Parallelableと基本的に同じですが、Serializableでうまくいくことを除けば、Externalizableを実装しています。

ObjectOutputStream自体はSerializableでもParcelableでもないですが、ByteArrayOutputStreamにそれを指示し、周りの結果のバイト配列を渡すことができます。

public static byte[] serialize(Externalizable object) { 
    final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 

    ObjectOutputStream objectStream = null; 
    try { 
     objectStream = new ObjectOutputStream(buffer); 
     objectStream.writeObject(object); 
    } catch (IOException e) { 
     throw new RuntimeException(e); 
    } finally { 
     if (objectStream != null) { 
      try { objectStream.close(); } catch (IOException ignored) {} 
     } 
    } 

    return buffer.toByteArray(); 
} 

public static <T extends Externalizable> T deserialize(byte[] bytes) { 
    ObjectInputStream objectStream = null; 
    try { 
     objectStream = new ObjectInputStream(new ByteArrayInputStream(bytes)); 
     return (T) objectStream.readObject(); 
    } catch (IOException | ClassNotFoundException e) { 
     throw new RuntimeException(e); 
    } finally { 
     if (objectStream != null) { 
      try { objectStream.close(); } catch (IOException ignored) {} 
     } 
    } 
} 

をそしてここで、あなたのクラスは、今どのように見えるかです:

俳優:

class Actor implements Externalizable { 
    private String name; 
    private Movie movie; 

    public Actor(String name, Movie movie) { 
    this.name = name; 
    this.movie = movie; 
    } 

    // required by Externalizable contract 
    public Actor() { 
    } 

    @Override 
    public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { 
    name = input.readUTF(); 
    movie = (Movie) input.readObject(); 
    } 

    @Override 
    public void writeExternal(ObjectOutput output) throws IOException { 
    output.writeUTF(name); 
    output.writeObject(movie); 
    } 

    ... 
} 

映画:

class Movie implements Externalizable { 
    private List<Actor> actors; 

    private int year; 

    public Movie(int year) { 
    this.year = year; 

    actors = new ArrayList<>(); 
    } 

    public void addActors(Actor... actors) { 
    Collections.addAll(this.actors, actors); 
    } 

    // required by Externalizable contract 
    public Movie() { 
    } 

    @Override 
    @SuppressWarnings("unchecked") 
    public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { 
    year = input.read(); 
    actors = (List<Actor>) input.readObject(); 
    } 

    @Override 
    public void writeExternal(ObjectOutput output) throws IOException { 
    output.write(year); 
    output.writeObject(actors); 
    } 

    ... 
} 

私はちょうど私のデバイスでテストし、Intentを介してアクティビティ間で相互参照するムービー/アクターを正常に渡すことができました。

+0

申し訳ありません、それはAndroidです。 – ThirdMartian

+0

あなたは私の提案を本当に理解していないようです。いくつかのサンプルコードを追加しました。これが役立つことを願っています。 – user1643723

0

ParcelableMovieオブジェクトを書きながらこれは、あなたが本当にActor内からMovieへの参照が必要な場合はMovieクラスにIDを追加してみてくださいとActorにこのIDを与えることができる、無限ループを作成します。後でこのIDを使用して対応するMovieを追跡することもできます。これはまだあなたの要件を満たしているかどうかわかりません。とにかく、循環参照を使用することは、オブジェクト指向言語では強く推奨されません。

関連する問題