2009-11-11 6 views
8

ऐसा प्रतीत होता है कि पार्ससेल योग्य सर्किलिज़ेबल करता है जैसे सर्कुलर संदर्भों को गहन रूप से संभाल नहीं करता है। निम्न उदाहरण में, बार के क्रमबद्धता बस ठीक काम करता है, लेकिन यह एक पार्सल के लिए लिख एक stackoverflow कारण बनता है:सर्कुलर संदर्भों के साथ पार्ससेलबल का उपयोग

I/TestRunner(1571): java.lang.StackOverflowError 
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) 
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); 
    } 


} 

मैं Parcelable वृत्तीय संदर्भ का उपयोग करता है करने के लिए Serializable का उपयोग करने से अधिक कुछ कोड बंदरगाह के लिए कोशिश कर रहा हूँ। पार्ससेल के साथ इसे संभालने के लिए क्या कोई अच्छी रणनीति है?

+0

तो क्या आपने कभी इसे समझ लिया? –

+0

दुर्भाग्यवश, नहीं – emmby

उत्तर

1

शायद उत्तर लिखने के लिए एक अधिक बुद्धिमान सेट में है और फॉरपार्सेल तरीकों का निर्माण?

मेरे सिर के ऊपर से, आप उन ऑब्जेक्ट्स की एक सूची रख सकते हैं जिन्हें आपने पहले से ही किसी दिए गए पार्सल पर लिखा है और उन्हें केवल टैग (उनकी स्थानीय पहचान हैशकोड(), शायद) द्वारा पहचानें। (ध्यान दें कि यह एक वैश्विक सूची नहीं है, यह स्पष्ट रूप से प्रति-पार्सल है; शायद स्वयं अर्ध-ग्लोबल 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-बिट JVMs (अंतर्निहित सी ++ पॉइंटर का मान होता है) पर होता है। सादा hashCode() सार्थक हो सकता है (शायद टाइपिंग जानकारी के अतिरिक्त के साथ?), या शायद कुछ प्रकार का सीरियल नंबर।

एक अन्य विकल्प सिर्फ सादे एक byte[] करने के लिए अपने वस्तुओं को क्रमानुसार और लिखते हैं कि Parcel में करने के लिए हो सकता है, लेकिन यह मुझे थोड़ी अक्षम हमलों ...

0

उपयोग जावा क्रमांकन। Parcelable के बजाय अपनी कक्षा Externalizable का विस्तार करें और इसे ऑब्जेक्टऑटपुटस्ट्रीम का उपयोग करके बाइट सरणी में परिवर्तित करें। इस बाइट सरणी को दूसरी तरफ [1][2] पास करें और ऑब्जेक्टइनपुटस्ट्रीम का उपयोग करके इसे deserialize करें।

एंड्रॉइड पार्ससेलबल्स बहुत तेज़ हैं, लेकिन यह गति सभी अतिरिक्त कार्यक्षमताओं की लागत पर आती है, परंपरागत रूप से धारावाहिक ढांचे में मौजूद है।

जावा क्रमबद्धता को शक्तिशाली और लचीला होने के लिए डिज़ाइन किया गया था और सर्कुलर संदर्भों को संभालने सहित कई चीजों के लिए समर्थन शामिल है। यदि आप कस्टम serialVersionUID (रनटाइम पर इसकी प्रतिबिंबित गणना से बचने के लिए) घोषित करते हैं और मैन्युअल रूप से पढ़ने/कक्षा में पढ़ने के लिए कक्षा सामग्री को पढ़ते हैं, तो आपको पार्सेलबल के साथ लगभग समान प्रदर्शन मिलेगा (जहां "लगभग" गोलाकार संदर्भों को ट्रैक रखने पर "लगभग" खर्च किया जाता है और)।