我有两个课程,我们假设他们看起来像这样:
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
}
现在,当我尝试将Movie写入parcelable时,我得到了StackOverflowError:
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写入Parcel时,它会尝试编写Actor,但在Actor中它会尝试再次编写Movie。
问题
如何避免嵌套类的问题?
答案 0 :(得分:0)
请勿将Movie
存储在Actor
内。它们之间的双向关系正在产生错误。
此外,Actor
应存储Movie
甚至没有意义。一个现实生活中的演员可以在很多电影中播放,也可以不播放,也可以只播放电视剧。
答案 1 :(得分:0)
改为实施Externalizable。然后使用writeObject序列化带有对象标识帐户的引用。
Java序列化协议旨在处理对象之间的循环相互依赖性。 Parcelables不支持那些设计 - 试图破解这种支持会毫无意义地重复工作,已由ObjectInputStream
和ObjectOutputStream
的创建者完成。注意,我并不是建议实现Serializable(由于基于反射而很慢),而是实现Externalizable,它与Parcelable基本相同,只不过它可以很好地与序列化一起使用。
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成功地跨活动传递交叉引用的电影/演员。
答案 2 :(得分:0)
如果您真的需要Movie
内的Parcelable
引用,那么在将Movie
对象写入Actor
时会创建一个无限循环在Movie
类中添加ID并将此ID提供给Actor
,之后您可以使用此ID跟踪相应的Movie
,但我不确定这是否仍符合您的要求。无论如何,在OO语言中强烈反对使用循环引用。