UPBReader – Weitergabe einer Objektstruktur von Activity zu Activity in Android

14 Dez

In meinem UPBReader kann zu einem bestimmten Teil des Textes eines eBooks eine Annotation (Notiz) hinzugefügt werden. Sämtliche Informationen dieser Annotation sind in einer Objektstruktur gespeichert. Nun soll beim Tippen auf eine Annotation diese bearbeitet werden können. Dies wird innerhalb einer separaten Activity geschehen. Also muss dieser Activity natürlich auch die Objektstruktur zur Verfügung stehen. Genau für diese Problematik gibt es die verschiedensten Möglichkeiten. Normal werden in Android, zumindest Primitive, direkt oder in einem Bundle über ein Intent an die neue Activity weitergegeben. Mit Objekten ist das mit Hilfe des Parcelable Ansatzes ebenfalls möglich. Dabei implementiert die betroffene Klasse das Interface Parcelable, was bedeutet, dass diese Klasse in ein Parcel (Marshalling) transformiert werden kann und auch wieder zurück (Unmarshalling). Aber warum eigentlich Parcelable, wenn es auch die normale Java-Serialisierung gibt? Der Vorteil von einem Parcel im Gegensatz zur normalen Java-Serialisierung ist, dass Parcels extra für hohe Effizienz entworfen wurden und deshalb in Android Anwendungen vorgezogen werden sollten.

Jedenfalls möchte ich zeigen was dafür notwendig ist, denn der Aufwand ist höher als die Verwendung von Java-Serialisierung. Zunächst muss wie bereits erwähnt meine Klasse Annotation das Interface Parcelable implementieren.

public class Annotation implements Parcelable { protected int id; protected ArrayList<String> tags; protected Author author; ... }

Durch das Interface Parcelable müssen zwei Methoden implementiert werden wovon uns nur die writeToParcel Methode interessieren soll. Diese wird für das schreiben der Daten des aktuellen Objektes in das Parcel benutzt. Es müssen dabei alle lokalen Variablen per entsprechenden mit Typ versehenen write-Befehlen in das Parcel geschrieben werden, wie in writeToParcel unten zu sehen ist. Dabei gibt es für die meisten Datentypen die richtigen write-Befehle. Das Vorgehen wird hier beispielhaft an den Typen Integer, String ArrayList und Author gezeigt. Author ist dabei eine eigene Klasse, die wiederum das Interface Parcelable implementiert und dies auch muss.

@Override public int describeContents() { return 0; } @Override  public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeStringList(tags); dest.writeParcelable(author, flags); }

Also haben wir die Methode, um ein Parcel mit Daten zu füllen. Nun muss es aber zusätzlich die Möglichkeit geben, aus dem Parcel wieder die Objektstruktur mit allen Daten zu generieren. Deshalb gibt es für ein Parcel ebenfalls einen read-Befehl für jeden der verschiedenen Datentypen. Diese werden innerhalb eines zusätzlichen Konstruktors benutzt, der ein Parcel entgegennimmt und daraus die Daten wieder herstellt.

private Annotation(Parcel in) { id = in.readInt(); if (tags == null) { tags = new ArrayList(); } in.readStringList(tags); author = in.readParcelable( Author.class.getClassLoader()); }

Zusätzlich muss das Creator Interface implementiert werden. Damit wird aus einem Parcel wieder eine Instanz der aktuellen Klasse erzeugt, indem der neue Konstruktor aufgerufen wird.

public static final Parcelable .Creator<Annotation> CREATOR =  new Parcelable.Creator<Annotation>() { public Annotation createFromParcel(Parcel in) { return new Annotation(in); } public Annotation[] newArray(int size) { return new Annotation[size]; } };

Das war alles, was in der Klasse Annotation an zusätzlicher Code nötig ist. Dem Intent, das an die neue Activity übergeben wird, kann nun eine Instanz der Annotation-Klasse als Parcel hinzugefügt werden.

Intent i = new Intent(getApplicationContext(), NewActivity.class); i.putExtra( "annotation", annotation; startActivity(i);

In der neuen Activity-Klasse in onCreate() kann nun wie unten zu sehen aus dem Parcel wieder ein Annotation-Objekt erzeugt werden.

Intent i = getIntent(); Annotation annotation = (Annotation) i.getParcelableExtra("annotation");

Der hier beispielhaft aufgeführte Quellcode ist alles andere als Vollständig. Meine Objektstruktur hat mehrere Ebenen, von denen ich alle enthaltenen Klassen Parcelable implementieren lies. Zusätzlich ist mir eine Besonderheit aufgefallen. Es gibt zwar viele read bzw. write Methoden für Parcels, aber keine die das Schreiben oder Lesen von einem normalen boolean Wert übernimmt. Dafür musste ich einen einfachen Workaround verwenden, bei dem ich zunächst wie folgt den boolean Wert in einen Byte Wert umgewandelt habe.

dest.writeByte((byte) (booleanWert ? 1 : 0));

Das musste natürlich beim Unmarshalling auch wieder rückgängig gemacht werden.

booleanWert = in.readByte() == 1;

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: