Wie lese / schreibe ich einen Booleschen Wert bei der Implementierung der Parcelable-Schnittstelle?

404

Ich versuche, ArrayList Parcelableeine Liste benutzerdefinierter Objekte zu erstellen, um sie an eine Aktivität zu übergeben. Ich beginne eine myObjectListKlasse zu schreiben , die erweitert ArrayList<myObject>und implementiert Parcelable.

Einige Attribute von MyObjectsind boolean, Parcelhaben aber keine Methode read/writeBoolean.

Was ist der beste Weg, um damit umzugehen?

grunk
quelle
3
Weil all das Lesen, das ich über das Übergeben von Objekten zwischen Aktivitäten gemacht habe, die Verwendung von parcelable anstelle von serialisable vorkonfiguriert.
Grunk
10
@MisterSquonk Sie sollten die SerializableSchnittstelle nicht für die Kommunikation zwischen Aktivitäten verwenden. Es ist langsam.
Octavian A. Damiean
1
@grunk: OK, das ist fair genug, aber bis Intent.putExtra (Stringname, serialisierbarer Wert) in den Dokumenten als veraltet markiert ist, werde ich es gerne weiter verwenden, wenn es mir das Leben leichter macht. Nur ein Gedanke.
Squonk
3
@ Octavian: Aber das hängt von einer Fallstudie ab und ist relativ.
Squonk
2
Meiner Meinung nach ist das Architektenteam von Android faul !!! wo ist boolean !!!!!!!!
Mateus

Antworten:

942

So würde ich es machen ...

writeToParcel:

dest.writeByte((byte) (myBoolean ? 1 : 0));     //if myBoolean == true, byte == 1

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0
b_yng
quelle
38
Kein Grund, Byte über int zu verwenden. Byte ist aufgrund der Besetzung ausführlicher: dest.writeInt (myBoolean? 1: 0);
Miguel
Warum hat der @ SiPlus-Kommentar so viele positive Stimmen erhalten? Weder 1 noch 0 werden überhaupt "geladen". Es macht absolut keinen Unterschied. Und seit wann ist Java eine schwach typisierte Sprache?
niemand
13
@sotrh Schreiben eines Bytes schreibt nur ein int:/** * Write a byte value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeByte(byte val) { writeInt(val); }
Dallas
3
@ Dallas ist das aus der Dokumentation? Wenn ja, dann ignoriere meinen Kommentar. Scheint unaufrichtig für die API, eine Funktion zu haben, die sagt writeByte, aber tatsächlich ein int schreibt.
Sotrh
1
@sotrh, das ist ein Kopieren und Einfügen aus einem Quellcode. Öffnen Sie die android.os.Parcel-Quelle und überzeugen Sie sich selbst.
Jaroslaw Mytkalyk
66

Sie können auch die writeValue- Methode verwenden. Meiner Meinung nach ist das die einfachste Lösung.

dst.writeValue( myBool );

Danach können Sie es einfach mit einer einfachen Besetzung abrufen, um Boolean:

boolean myBool = (Boolean) source.readValue( null );

Unter der Haube wird das Android Framework es als Ganzzahl behandeln:

writeInt( (Boolean) v ? 1 : 0 );
Taig
quelle
Android-Quelle mit dem Teil "unter der Haube" (l. 1219). Obwohl diese Methode ein wenig weniger effizient ist (aufgrund des Methodenaufrufs und des Schalters), liest sie sich etwas unkomplizierter.
Desseim
6
Der hier geschriebene Code wird nicht kompiliert. readValue erfordert einen Klassenladeprogramm, wird jedoch für Boolesche Werte nicht benötigt. Es sollte lauten "boolean myBool = (Boolean) source.readValue (null);" Rezensenten, die keine Ahnung haben, was sie tun, und meine Bearbeitung dieser Antwort abgelehnt haben: @hemang, jeeped, DavidRR.
Miguel
1
@ Miguel Das stimmt, behoben :)
Taig
15

Sie erklären so

 private boolean isSelectionRight;

schreiben

 out.writeInt(isSelectionRight ? 1 : 0);

lesen

isSelectionRight  = (in.readInt() == 0) ? false : true;

Der boolesche Typ muss in etwas konvertiert werden, das Parcel unterstützt, damit wir ihn in int konvertieren können.

Shaista Naaz
quelle
Dies verursacht einen Fehler, inkompatible Typen, erforderlich Boolescher Wert gefunden int?
Paul Okeke
12

In AndroidStudio (mit 2,3 atm) können Sie nach der Implementierung von Parcelable in Ihrer Klasse einfach den Mauszeiger über den Klassennamen halten und werden aufgefordert, die Parcelable-Implementierung hinzuzufügen:

Geben Sie hier die Bildbeschreibung ein

Aus den vier Feldern wird Folgendes generiert:

public class YourClass implements Parcelable{

String someString;
int someInt;
boolean someBoolean;
List<String> someList;

protected YourClass(Parcel in) {
    someString = in.readString();
    someInt = in.readInt();
    someBoolean = in.readByte() != 0;
    someList = in.createStringArrayList();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(someString);
    dest.writeInt(someInt);
    dest.writeByte((byte) (someBoolean ? 1 : 0));
    dest.writeStringList(someList);
}

...
Henk-Martijn
quelle
Das ist praktisch :)
Dino Tw
8

Ich habe sie normalerweise in einem Array und rufe writeBooleanArrayund anreadBooleanArray

Wenn es sich um einen einzelnen Booleschen Wert handelt, den Sie packen müssen, können Sie Folgendes tun:

parcel.writeBooleanArray(new boolean[] {myBool});
Geobits
quelle
Haben Sie jemals ein Problem gehabt, wenn Sie ein paar Boolesche Mengen paketieren müssen ... das habe ich. Könnten Sie mir bitte helfen? stackoverflow.com/questions/13463727/… . Vielen Dank.
Roger Alien
8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read
Meghna
quelle
5

Ich habe Ihnen vorgeschlagen, Parcelable am einfachsten zu implementieren, wenn Sie Android Studio verwenden.

Gehen Sie einfach zu Datei-> Einstellungen-> Plugins-> Repository durchsuchen und suchen Sie nach einem Paket. Siehe Bild

Geben Sie hier die Bildbeschreibung ein Es wird automatisch Parcelable erstellt.

Und dafür gibt es auch eine Website. http://www.parcelabler.com/

Zar E Ahmer
quelle
4

Kurze und einfache Implementierung in Kotlin mit nullbarer Unterstützung:

Fügen Sie dem Paket Methoden hinzu

fun Parcel.writeBoolean(flag: Boolean?) {
    when(flag) {
        true -> writeInt(1)
        false -> writeInt(0)
        else -> writeInt(-1)
    }
}

fun Parcel.readBoolean(): Boolean? {
    return when(readInt()) {
        1 -> true
        0 -> false
        else -> null
    }
}

Und benutze es:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false
Pavel Shorokhov
quelle
@AliKazi Sie können dies nicht in einer einzeiligen Anweisung in Java mit Unterstützung optionaler Typen tun. Sie sollten 3 Zustände beibehalten. Ich denke du vergisst null.
Pavel Shorokhov
@ comm1x, Die IDE mag diese Lösung nicht. `Kann nicht auf" readBoolean "zugreifen, bevor der Superklassenkonstruktor aufgerufen wurde.
Adam Hurwitz
@ comm1x Ich habe das Problem behoben. Um arbeiten zu können, müssen sich die hinzugefügten Methoden im Begleitobjekt befinden
Adam Hurwitz
3

Sie können Ihre booleschen Werte durch Maskieren und Verschieben in ein Byte packen. Das wäre der effizienteste Weg, und wahrscheinlich ist es das, was sie von Ihnen erwarten würden.

Flotteway76
quelle
+1. Richtig, das Speichern des Werts in einem Byte wäre effizienter. Würde es Ihnen etwas ausmachen, wenn ich meine Frage bearbeite, um Ihre Idee darzustellen?
Octavian A. Damiean
Sie können, aber was Sie geschrieben haben, ist nicht wirklich das, was ich meinte. Es wird funktionieren, ist aber nicht das effizienteste. Sie können 8 Boolesche Werte mit Masken und Boolescher Algebra in ein Byte packen
Flotteway76
In den meisten Fällen stimme ich Ihnen zu, aber ich habe Fälle, die sich von Zeit zu Zeit einschleichen und in denen ich drei Zustände benötige, mit denen Boolean arbeitet. Wie eine optionale Ja / Nein-Frage. Ich brauche die Null, um zu wissen, ob der Boolesche Wert explizit angegeben wurde oder nicht.
Chad Gorshing
Es gibt keinen Grund, Byte über int zu verwenden, da die writeByte()Methode des writeInt()
Pakets
3

Es ist schwer, die eigentliche Frage hier zu identifizieren. Ich denke, es ist, wie man mit Booleschen Werten umgeht, wenn man die ParcelableSchnittstelle implementiert .

Einige Attribute von MyObject sind boolesch, aber Parcel hat keine Methode read / writeBoolean.

Sie müssen den Wert entweder als Zeichenfolge oder als Byte speichern. Wenn Sie sich für eine Zeichenfolge entscheiden, müssen Sie die statische Methode der Stringaufgerufenen Klasse verwenden valueOf(), um den booleschen Wert zu analysieren. Es ist nicht so effektiv wie das Speichern in einem harten Byte.

String.valueOf(theBoolean);

Wenn Sie sich für ein Byte entscheiden, müssen Sie selbst eine Konvertierungslogik implementieren.

byte convBool = -1;
if (theBoolean) {
    convBool = 1;
} else {
    convBool = 0;
}

Wenn Sie das ParcelObjekt entfernen , müssen Sie sich um die Konvertierung in den ursprünglichen Typ kümmern.

Octavian A. Damiean
quelle
Es gibt absolut keinen Grund, String zu verwenden. Es gibt keinen Grund, Byte über int zu verwenden, da die Paketmethode writeByte()direkt aufruft writeInt(). Die Konvertierungslogik ist zu ausführlich. Tun Sie es einfach writeInt(boolean ? 1 : 0)undboolean = readInt() != 0
Yaroslav Mytkalyk
1

Diese Frage wurde bereits von anderen perfekt beantwortet, wenn Sie es selbst tun möchten.

Wenn Sie es vorziehen, den größten Teil des Paketcodes auf niedriger Ebene zu kapseln oder zu verbergen, können Sie einen Teil des Codes verwenden, den ich vor einiger Zeit geschrieben habe, um die Handhabung von Paketen zu vereinfachen.

Das Schreiben auf ein Paket ist so einfach wie:

parcelValues(dest, name, maxSpeed, weight, wheels, color, isDriving);

Dabei ist Farbe beispielsweise eine Aufzählung und isDriving ein Boolescher Wert.

Das Lesen von einem Paket ist auch nicht viel schwieriger:

color = (CarColor)unparcelValue(CarColor.class.getClassLoader());
isDriving = (Boolean)unparcelValue();

Schauen Sie sich einfach das "ParceldroidExample" an, das ich dem Projekt hinzugefügt habe.

Schließlich hält es auch den CREATOR-Initialisierer kurz:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);
Michael Geier
quelle
Danke für .class.getClassLoader().
CoolMind
0

Es gibt viele Beispiele in den Android (AOSP) -Quellen. Die PackageInfoKlasse hat beispielsweise ein boolesches Element requiredForAllUsersund wird wie folgt serialisiert:

public void writeToParcel(Parcel dest, int parcelableFlags) {
    ...
    dest.writeInt(requiredForAllUsers ? 1 : 0);
    ...
}

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
FireAphis
quelle