Come leggere / scrivere un booleano durante l'implementazione dell'interfaccia Parcelable?


404

Sto cercando di creare un ArrayList Parcelableper passare a un'attività un elenco di oggetti personalizzati. Comincio a scrivere una myObjectListclasse che si estende ArrayList<myObject>e implementa Parcelable.

Alcuni attributi di MyObjectsono booleanma Parcelnon hanno alcun metodo read/writeBoolean.

Qual è il modo migliore per gestirlo?


3
Perché tutte le letture che ho fatto sul passaggio di oggetti tra le attività preconizzano l'uso del parcelable anziché del serializzabile.
grunk

10
@MisterSquonk Non utilizzare l' Serializableinterfaccia per la comunicazione tra attività. È lento.
Ottaviano A. Damiano,

1
@grunk: OK, è abbastanza giusto ma fino a quando Intent.putExtra (nome stringa, valore serializzabile) è contrassegnato come deprecato nei documenti, sarò felice di continuare a usarlo se mi semplifica la vita. Solo un pensiero.
Squonk,

3
@ Ottaviano: ma dipende da uno studio per caso ed è relativo.
Squonk,

2
secondo me, il team di architetti di Android è pigro !!! dove è booleano !!!!!!!!
Mateus

Risposte:


942

Ecco come lo farei ...

writeToParcel:

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

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0

38
Nessun motivo per utilizzare byte su int. byte è più dettagliato a causa del cast: dest.writeInt (myBoolean? 1: 0);
Miguel

Perché i commenti di @SiPlus hanno ottenuto così tanti voti positivi? Né 1, né 0 viene "caricato" affatto. Non fa assolutamente alcuna differenza. E da quando Java è un linguaggio debolmente tipizzato?
nessuno il

13
@sotrh scrivendo un byte scrive solo un 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 è quello dalla documentazione? In tal caso, ignora il mio commento. Sembra disonesto che l'API abbia una funzione che dice writeByte, ma in realtà scrive un int.
sotrh,

1
@sotrh che è un copia-incolla da un codice sorgente. Apri android.os.Parcel source e vedi di persona.
Yaroslav Mytkalyk,

66

È inoltre possibile utilizzare il metodo writeValue . Secondo me questa è la soluzione più semplice.

dst.writeValue( myBool );

Successivamente puoi recuperarlo facilmente con un semplice cast per Boolean:

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

Sotto il cofano Android Framework lo gestirà come un numero intero:

writeInt( (Boolean) v ? 1 : 0 );

sorgente Android che mostra la parte "under the hood" (l. 1219). Anche se un po 'meno efficiente (a causa della chiamata del metodo e dello switch), questo metodo è un po' più semplice.
Desseim,

6
Il codice come scritto qui non verrà compilato. readValue richiede un classloader ma non è necessario per i booleani. Dovrebbe leggere "boolean myBool = (Boolean) source.readValue (null);" I revisori che non hanno idea di cosa stiano facendo e hanno rifiutato la mia modifica a questa risposta: @hemang, jeeped, DavidRR.
Miguel

1
@miguel È vero, riparato :)
Taig

15

dichiari così

 private boolean isSelectionRight;

Scrivi

 out.writeInt(isSelectionRight ? 1 : 0);

leggere

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

il tipo booleano deve essere convertito in qualcosa che Parcel supporta e quindi possiamo convertirlo in int.


Ciò causa un errore, tipi incompatibili, booleano richiesto trovato int?
Paul Okeke,

12

AndroidStudio (usando 2.3 atm), dopo aver implementato Parcelable sulla tua classe, puoi semplicemente tenere il puntatore del mouse sul nome della tua classe e ti chiede di aggiungere l'implementazione parcelable:

inserisci qui la descrizione dell'immagine

Dai quattro campi, genera quanto segue:

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);
}

...

È utile :)
Dino Tw,

8

Normalmente li ho in un array e chiamare writeBooleanArrayereadBooleanArray

Se è un singolo booleano che devi mettere in valigia, puoi farlo:

parcel.writeBooleanArray(new boolean[] {myBool});

Hai mai avuto problemi quando hai bisogno di pacchi di pochi booleani ... ho. Potresti per favore aiutarmi>? stackoverflow.com/questions/13463727/… . Grazie.
Roger Alien,

8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read

5

Ti ho suggerito il modo più semplice per implementare Parcelable se stai usando Android Studio.

Vai su File-> Impostazioni-> Plugin-> Sfoglia repository e cercare i pacchi. Vedi immagine

inserisci qui la descrizione dell'immagine Creerà automaticamente Parcelable.

E c'è anche un webiste per farlo. http://www.parcelabler.com/


4

Implementazione breve e semplice in Kotlin , con supporto nullable:

Aggiungi metodi al pacco

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
    }
}

E usalo:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false

@AliKazi non puoi farlo in un'istruzione a 1 riga in Java con tipi opzionali di supporto. Dovresti persistere 3 stati. Penso che ti dimentichi di null.
Pavel Shorokhov,

@ comm1x, L'IDE non piace questa soluzione. `Impossibile accedere a" readBoolean "prima che il costruttore della superclasse sia stato chiamato.
Adam Hurwitz,

@ comm1x Ho risolto il problema. Per funzionare, i metodi aggiunti devono essere all'interno dell'oggetto associato
Adam Hurwitz,

3

È possibile comprimere i valori booleani in un byte utilizzando mascheramento e spostamento. Sarebbe il modo più efficace per farlo ed è probabilmente quello che si aspetterebbero che tu faccia.


+1. È vero, salvare il valore in un byte sarebbe più efficiente. Ti dispiacerebbe modificare la mia domanda per rappresentare la tua idea?
Ottaviano A. Damiano,

Puoi, ma quello che hai scritto non è proprio quello che intendevo dire. Funzionerà ma non è il più efficiente. Puoi racimolare 8 booleani in un byte usando maschere e algebra booleana
fleetway76

Nella maggior parte dei casi sono d'accordo con te, tuttavia ho casi che si insinuano di volta in volta in cui ho bisogno di tre stati con cui Boolean lavorerà. Come una domanda sì / no facoltativa. Ho bisogno del null per sapere se il booleano è stato esplicitamente specificato o meno.
Chad Gorshing,

Non vi è alcun motivo per utilizzare byte su int, poiché il writeByte()metodo del pacco chiama direttamentewriteInt()
Yaroslav Mytkalyk,

3

È difficile identificare la vera domanda qui. Immagino sia come gestire i booleani durante l'implementazione Parcelabledell'interfaccia.

Alcuni attributi di MyObject sono booleani ma Parcel non ha alcun metodo read / writeBoolean.

Dovrai memorizzare il valore come stringa o come byte. Se cerchi una stringa, dovrai usare il metodo statico della Stringclasse chiamata valueOf()per analizzare il valore booleano. Non è efficace come salvarlo in un byte difficile.

String.valueOf(theBoolean);

Se cerchi un byte dovrai implementare tu stesso una logica di conversione.

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

Quando si annulla il marshalling Parceldell'oggetto, è necessario occuparsi della conversione nel tipo originale.


Non c'è assolutamente alcun motivo per usare String. Non vi è alcun motivo per utilizzare byte su int, poiché il writeByte()metodo del pacchetto chiama direttamente writeInt(). La logica di conversione è troppo dettagliata. Basta fare writeInt(boolean ? 1 : 0)eboolean = readInt() != 0
Yaroslav Mytkalyk il

1

A questa domanda è già stata data una risposta perfetta da altre persone, se si desidera farlo da soli.

Se preferisci incapsulare o nascondere la maggior parte del codice di parceling di basso livello, potresti prendere in considerazione l'utilizzo di parceling parte del codice che ho scritto qualche tempo fa per semplificare la gestione dei pacchi.

Scrivere su un pacco è semplice come:

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

dove color è un enum e isDriving è un booleano, per esempio.

Anche leggere da un pacco non è molto più difficile:

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

Dai un'occhiata al "ParceldroidExample" che ho aggiunto al progetto.

Infine, mantiene breve l'inizializzatore CREATOR:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);

Grazie per .class.getClassLoader().
CoolMind,

0

Ci sono molti esempi nelle fonti Android (AOSP). Ad esempio, la PackageInfoclasse ha un membro booleano requiredForAllUsersed è serializzata come segue:

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

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.