2016-06-24 29 views
0

Wie Parcelable für einen Baum wie Struktur zu schreiben, die eine Base Klasse mit zwei Implementierungen haben, einen einen Node Typen und den anderes einen Container Typ, das eine Liste von Base Typen enthält.Android Parcel mit Baum von generischem Typ

Entschuldigung für die Masse des Codes unten. Die grundlegende Datenstruktur ist klein, aber ich habe meine aktuelle Parcelable Implementierung, die nicht funktioniert.

Ich habe versucht, ein Byte in der Basis writeToParcel hinzufügen, die den Typ angibt, um beim Unparzellieren zu erstellen, aber das scheint nicht zu funktionieren.

Das Problem ist, dass ich verschiedene Daten zurückbekomme, wenn ich ein Base Objekt paketiere, das einen tiefen Baum von Container Objekten enthält.

Irgendwelche Ideen zu was ich falsch mache?

Auch Ideen zur Implementierung von Komponententests für Parcelable s wären willkommen.

Base Class

public abstract class Base implements Parcelable { 
    public int val; 
    protected Base(final int val) { 
     this.val = val; 
    } 


    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeByte((byte) (this instanceof NodeBase ? 0 : 1)); 
     dest.writeInt(this.val); 
    } 

    protected Base(Parcel in) { 
     this.val = in.readInt(); 
    } 

    public static final Creator<Base> CREATOR = new Creator<Base>() { 
     @Override 
     public Base createFromParcel(Parcel source) { 
      return source.readByte() == 0 ? new NodeBase(source) : new ContainerBase(source); 
     } 

     @Override 
     public Base[] newArray(int size) { 
      return new Base[size]; 
     } 
    }; 
} 

Knotenklasse

public class NodeBase extends Base { 

    public final String name; 

    public NodeBase(final int val, final String name) { 
     super(val); 
     this.name = name; 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     super.writeToParcel(dest, flags); 
     dest.writeString(this.name); 
    } 

    protected NodeBase(Parcel in) { 
     super(in); 
     this.name = in.readString(); 
    } 

    public static final Creator<NodeBase> CREATOR = new Creator<NodeBase>() { 
     @Override 
     public NodeBase createFromParcel(Parcel source) { 
      return new NodeBase(source); 
     } 

     @Override 
     public NodeBase[] newArray(int size) { 
      return new NodeBase[size]; 
     } 
    }; 
} 

Container Klasse

public class ContainerBase extends Base { 
    public final List<Base> baseList; 

    public ContainerBase(final int val, final List<Base> baseList) { 
     super(val); 
     this.baseList = baseList; 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     super.writeToParcel(dest, flags); 
     dest.writeTypedList(this.baseList); 
     dest.writeInt(this.val); 
    } 

    protected ContainerBase(Parcel in) { 
     super(in); 
     this.baseList = in.createTypedArrayList(Base.CREATOR); 
     this.val = in.readInt(); 
    } 

    public static final Creator<ContainerBase> CREATOR = new Creator<ContainerBase>() { 
     @Override 
     public ContainerBase createFromParcel(Parcel source) { 
      return new ContainerBase(source); 
     } 

     @Override 
     public ContainerBase[] newArray(int size) { 
      return new ContainerBase[size]; 
     } 
    }; 
} 

Antwort

0

Sie erwähnt Generische Typen, aber ich sehe keine generischen Typen in Ihrem Code. Alles, was ich sehe, sind Eltern und Kind geerbte Klassen. Aber davon aus, dass Ihre Knoten und Container sind generisch und dass sie einen allgemeinen Parameter T haben, wobei T ein beliebiges Objekt sein kann, die in Ihrem Knoten/Container gespeichert werden kann, dann sollte die folgende Lösung helfen:

Schritt 1. Speichern Sie die Klassen, die von Ihrer Allgemein Klasse als String in Ihrer Basisklasse erweitert:

public abstract class Base implements Parcelable { 
    private String containerClassName; 
    private String nodeClassName; 

Schritt 2. Stellen Sie sicher, dass Ihre generischen Klassen super() aufrufen, was Sie bereits getan haben.

Schritt 3. Alle Klassen, die von Ihrer generischen Klasse erstreckt muss die Klassennamen wie dies beim Bau angeben:

public class NewNode extends NodeBase { 

    public NodeBase() { 
     super(); 
     setClassNames(NewNode.class.getName()); // Base class setter method 
    } 

Schritt 4. In Ihrer Basisklasse können Sie dann Ihre Klassennamen in getClassLoader() wie folgt lesen/schreiben:

protected NodeBase(Parcel in) { 
    super(in); 
    this.containerClassName = in.readString(); 
    this.nodeClassName = in.readString(); 

    ClassLoader containerLoader; 
    ClassLoader nodeLoader; 
    try { 
     containerLoader = Class.forName(containerClassName).getClassLoader(); 
     nodeLoader = Class.forName(nodeClassName).getClassLoader(); 
    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 
    containerObject = in.readParcelable(containerLoader); 
    nodeObject = in.readParcelable(nodeLoader); 
    //... Other class members can go here 
} 

@Override 
public void writeToParcel(Parcel dest, int flags) { 
    super.writeToParcel(dest, flags); 
    dest.writeString(containerClassName); 
    dest.writeString(nodeClassName); 
    //... Other class members can go here 
}