android – 使用带有循环引用的Parcelable

android – 使用带有循环引用的Parcelable,第1张

概述Parcelable似乎没有优雅地处理像Serializable那样的循环引用.在下面的示例中,Bar的序列化工作正常,但将其写入Parcel会导致堆栈溢出: I/TestRunner( 1571): java.lang.StackOverflowErrorI/TestRunner( 1571): at android.os.Parcel.writeParcelable(Parcel.ja Parcelable似乎没有优雅地处理像Serializable那样的循环引用.在下面的示例中,bar的序列化工作正常,但将其写入Parcel会导致堆栈溢出:
I/TestRunner( 1571): java.lang.StackOverflowErrorI/TestRunner( 1571):    at androID.os.Parcel.writeParcelable(Parcel.java:1106)I/TestRunner( 1571):    at androID.os.Parcel.writeValue(Parcel.java:1029)I/TestRunner( 1571):    at com.XXX.util.ParcelableTest$bar.writetoParcel(ParcelableTest.java:209)I/TestRunner( 1571):    at androID.os.Parcel.writeParcelable(Parcel.java:1106)I/TestRunner( 1571):    at androID.os.Parcel.writeValue(Parcel.java:1029)I/TestRunner( 1571):    at com.XXX.util.ParcelableTest$Baz.writetoParcel(ParcelableTest.java:246)I/TestRunner( 1571):    at androID.os.Parcel.writeParcelable(Parcel.java:1106)I/TestRunner( 1571):    at androID.os.Parcel.writeValue(Parcel.java:1029)I/TestRunner( 1571):    at com.XXX.util.ParcelableTest$bar.writetoParcel(ParcelableTest.java:209)I/TestRunner( 1571):    at androID.os.Parcel.writeParcelable(Parcel.java:1106)I/TestRunner( 1571):    at androID.os.Parcel.writeValue(Parcel.java:1029)public voID testCircular() throws Exception {    final bar bar = new bar();    final Baz baz = new Baz(bar);    bar.baz = baz;    // First,serialize    final ByteArrayOutputStream bytes = new ByteArrayOutputStream();    new ObjectOutputStream(bytes).writeObject(bar);    final ByteArrayinputStream bytesIn = new ByteArrayinputStream(bytes.toByteArray());    final bar bar2 = (bar) new ObjectinputStream(bytesIn).readobject();    assertNotNull(bar2);    assertNotNull(bar2.baz);    assertEquals( bar2,bar2.baz.bar );    // Now try same thing using parcelable    final Parcel p = Parcel.obtain();    p.writeValue(bar); // FAIL!  StackOverflowError    p.setDataposition(0);    final bar bar3 = (bar) p.readValue(bar.class.getClassLoader());    assertNotNull(bar3);    assertNotNull(bar3.baz);    assertEquals( bar3,bar3.baz.bar );}protected static class bar implements Parcelable,Serializable {    private static final long serialVersionUID = 1L;    public static final Parcelable.Creator<bar> CREATOR = new Parcelable.Creator<bar>() {        public bar createFromParcel(Parcel source) {            final bar f = new bar();            f.baz = (Baz) source.readValue(bar.class.getClassLoader());            return f;        }        public bar[] newArray(int size) {            throw new UnsupportedOperationException();        }    };    public Baz baz;    public bar() {    }    public bar( Baz baz ) {        this.baz = baz;    }    public int describeContents() {        return 0;    }    public voID writetoParcel(Parcel dest,int ignored) {        dest.writeValue(baz);    }}protected static class Baz implements Parcelable,Serializable {    private static final long serialVersionUID = 1L;    public static final Parcelable.Creator<Baz> CREATOR = new Parcelable.Creator<Baz>() {        public Baz createFromParcel(Parcel source) {            final Baz f = new Baz();            f.bar = (bar) source.readValue(Baz.class.getClassLoader());            return f;        }        public Baz[] newArray(int size) {            throw new UnsupportedOperationException();        }    };    public bar bar;    public Baz() {    }    public Baz( bar bar ) {        this.bar = bar;    }    public int describeContents() {        return 0;    }    public voID writetoParcel(Parcel dest,int ignored) {        dest.writeValue(bar);    }}

我正在尝试将一些代码从使用Serializable转换为使用循环引用的Parcelable.使用Parcelable处理此问题是否有一个好的策略?

解决方法 也许答案在于一组更智能的writetoParcel和createFromParcel方法?

在我的脑海中,您可以保留已经完全写入给定Parcel的对象列表,并仅通过标记(可能是其本地IDentityHashCode())来标识它们. (请注意,这不是一个全局列表,它是明确的per-Parcel;也许它本身是通过半全局Map< Parcel,Set< Integer>>存储的?你需要确保一旦包裹遗忘了这个集合完全写了.)

writetoParcel()的相关位看起来像这样:

HashSet<Integer> set = getWrittenSetFor(dest);final int tag = IDentityHashCode();if (set.contains(tag)) {    // Already sent    dest.writeInt(tag);} else {    set.put(tag);    dest.writeInt(tag);    dest.writeValue(this);}

相应的createFromParcel()会稍微复杂一些.

我希望这种方法存在潜在的问题,但这是我开始的地方.正如我在这里所说的,它依赖于IDentityHashCode()保证对于不同的对象是不同的 – 它通常在32位JVM上(作为底层C指针的值).普通的hashCode()可能是值得的(可能添加了输入信息?),或者某种序列号.

另一个选择可能是将对象简单地序列化为byte []并将其写入Parcel,但它让我觉得有点低效……

总结

以上是内存溢出为你收集整理的android – 使用带有循环引用的Parcelable全部内容,希望文章能够帮你解决android – 使用带有循环引用的Parcelable所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1139194.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存