Wie implementiere ich Parcelable richtig mit einer ArrayList <Parcelable>?


76

Ich habe Probleme, meine Klasse zu machen Parcelable. Das Problem ist, ich versuche, ein Mitglied in der Klasse, das ein ArrayList<Parcelable>Objekt ist, auf das Paket zu schreiben . Das ArrayListist Serializableund die Objekte ( ZigBeeDev) in der Liste sind Parcelable.

Hier ist der relevante Code:

package com.gnychis.coexisyst;

import java.util.ArrayList;
import java.util.Iterator;

import android.os.Parcel;
import android.os.Parcelable;

public class ZigBeeNetwork implements Parcelable {

    public String _mac;             // the source address (of the coordinator?)
    public String _pan;             // the network address
    public int _band;               // the channel
    ArrayList<Integer> _lqis;       // link quality indicators (to all devices?)
    ArrayList<ZigBeeDev> _devices;  // the devices in the network

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(_mac);
        out.writeString(_pan);
        out.writeInt(_band);
        out.writeSerializable(_lqis);
        out.writeParcelable(_devices, 0);  // help here
    }

    private ZigBeeNetwork(Parcel in) {
        _mac = in.readString();
        _pan = in.readString();
        _band = in.readInt();
        _lqis = (ArrayList<Integer>) in.readSerializable();
        _devices = in.readParcelable(ZigBeeDev.class.getClassLoader());  // help here
    }

    public int describeContents() {
        return this.hashCode();
    }

    public static final Parcelable.Creator<ZigBeeNetwork> CREATOR = 
            new Parcelable.Creator<ZigBeeNetwork>() {
        public ZigBeeNetwork createFromParcel(Parcel in) {
            return new ZigBeeNetwork(in);
        }

        public ZigBeeNetwork[] newArray(int size) {
            return new ZigBeeNetwork[size];
        }
    };

    //...
}

Ich habe zwei Stellen mit "// help here" markiert, um zu verstehen, wie man richtig auf das Paket schreibt und es rekonstruiert. Wenn ZigBeeDevheißt Parcelable(richtig getestet), wie mache ich das richtig?

Antworten:


143

Sie haben es fast geschafft !

Sie müssen nur tun:

public void writeToParcel(Parcel out, int flags) {
    out.writeString(_mac);
    out.writeString(_pan);
    out.writeInt(_band);
    out.writeSerializable(_lqis);
    out.writeTypedList(_devices);
}

private ZigBeeNetwork(Parcel in) {
    _mac = in.readString();
    _pan = in.readString();
    _band = in.readInt();
    _lqis = (ArrayList<Integer>) in.readSerializable();
    in.readTypedList(_devices, ZigBeeDev.CREATOR);
}

Das ist alles!

Für Ihre Liste der Ganzzahlen können Sie außerdem Folgendes tun:

out.writeList(_lqis);
_lqis = new ArrayList<>();
in.readList(_lqis Integer.class.getClassLoader());

Es sollte funktionieren.


2
Zum späteren Nachschlagen, und ich bin mir nicht sicher, ob es sich um einen Tippfehler handelt, den niemand bemerkt hat, der aber ZigBeeDev.Creatorsein sollte ZigBeeDev.CREATOR. Ich habe jedes Mal einen Fehler erhalten, bis mir klar wurde, dass es zwei verschiedene Schöpfer gibt, die ich in meinem eigenen Projekt verwenden kann.
Gatlingxyz

@ NitroG42 Der zweite Ansatz für cannot convert from void to ArrayList<Integer>
Leseliste

8
Ich musste das Array auch vorher instanziieren. Beispiel: Mein Code würde folgendermaßen aussehen: _devices = new ArrayList <ZigBeeDev> (); in.readTypedList (_devices, ZigBeeDev.Creator);
Sgarman

@sgarman Es ist nicht erforderlich, die Array-Ursache zu instanziieren, dann erhalten Sie die Warnung: Explizites Typargument ZigBeeDev kann durch <> ersetzt werden. Diese Überprüfung meldet alle neuen Ausdrücke mit
Typargumenten,

Bestätigen Sie, dass Sie mit Generika arbeiten Hashtable, die Primitivtypen (einschließlich String) für einen seiner Schlüssel oder Werte verwenden.
Eido95

17

In meinem Fall in.readTypedList(_devices, ZigBeeDev.CREATOR);gab mir ein NullPointerExceptionauf _devices. Also habe ich folgendes benutzt:

_devices = in.createTypedArrayList(ZigBeeDev.CREATOR);

3
fwiw - Der Grund, warum Sie eine NPE erhalten haben, ist, dass Sie bei Verwendung zuerst in.readTypedList()eine neue ArrayList () erstellen und diese dann an die übergeben müssen. in.readTypedList(yourNewArrayList, YourObj.CREATOR)Andernfalls wird nur versucht, die Daten in eine Nullliste aufzunehmen.
RF43

Ja das ist richtig. Ich habe den Quellcode gelesen, bevor ich ihn verwendet habe. Vielen Dank für die zusätzlichen Informationen, die ich vergessen habe zu schreiben.
osrl

@osrl, wenn wir Ihrer Lösung folgen, bekam Ausnahme java.lang.OutOfMemoryError: Fehler beim Zuweisen einer 13893804-Byte-Zuordnung mit 11004100 freien Bytes und 10 MB bis OOM
Ajit Kumar Dubey

Enthält Ihr Array Dateien oder etwas Großes? @ Ajit
osrl


2

Im Konstruktor sollten Sie verwenden

_lqis = in.createTypedArrayList(ZigBeeDev.CREATOR);

Und in "writeToParcel" verwenden

out.writeTypedList(_lqis);

0

Ein bisschen spät, aber ich hatte auch dieses Problem. Nach langer Zeitverschwendung bin ich auf die Website parcelabler.com gestoßen, die automatisch Pakete für Sie erstellt.

Dadurch konnte ich sehr einfach ein verschachteltes Paket mit einer darin enthaltenen Array-Liste erstellen und viel Zeit sparen.

Grundsätzlich funktioniert die Website so, dass Sie Ihr Objekt mit der darin enthaltenen ArrayList eingeben und automatisch die erforderlichen Methoden hinzufügen, um es paketfähig zu machen (Lesen aus Paket, Schreiben in Paket, Beschreiben von Inhalten und Paketersteller werden automatisch generiert). Dies ist besonders nützlich, wenn Sie komplexe Pakete erstellen, wie in der hier gestellten Frage, die verschachtelte Pakete, Arrays und Listen enthalten.

BEARBEITEN: Auch IntelliJ IDEA und Android Studio haben Plugins dafür, die etwas Ähnliches wie die aufgelistete Website tun:

Diese Plugins generieren den Code für Android Parcelable- Boilerplates basierend auf Feldern in der Klasse.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.