¿Cómo leer / escribir un booleano al implementar la interfaz Parcelable?

404

Estoy tratando de hacer ArrayList Parcelableuna lista de objetos personalizados para pasar a una actividad. Empiezo a escribir una myObjectListclase que se extiende ArrayList<myObject>e implementa Parcelable.

Algunos atributos de MyObjectson booleanpero Parcelno tienen ningún método read/writeBoolean.

¿Cuál es la mejor manera de manejar esto?

grunk
fuente
3
Porque toda la lectura que he hecho sobre pasar objetos entre actividades preconiza el uso de parcelable en lugar de serialisable.
Grunk 01 de
10
@MisterSquonk No debe usar la Serializableinterfaz para la comunicación entre actividades. Es lento.
Octavian A. Damiean 01 de
1
@grunk: OK, eso es justo, pero hasta que Intent.putExtra (nombre de cadena, valor serializable) esté marcado como obsoleto en los documentos, estaré feliz de seguir usándolo si me facilita la vida. Solo un pensamiento.
Squonk
3
@Octavian: Pero eso depende de un estudio por caso y es relativo.
Squonk
2
en mi opinión, el equipo de arquitectos de android es vago !!! whereis boolean !!!!!!!!
Mateus

Respuestas:

942

Así es como lo haría ...

writeToParcel:

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

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0
b_yng
fuente
38
No hay razón para usar byte sobre int. byte es más detallado debido al reparto: dest.writeInt (myBoolean? 1: 0);
miguel
¿Por qué el comentario de @SiPlus obtuvo tantos votos positivos? Ni 1 ni 0 están "cargados" en absoluto. No hace absolutamente ninguna diferencia. ¿Y desde cuándo Java es un lenguaje débilmente tipado?
nadie
13
@sotrh escribiendo un byte solo escribe 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 es eso de la documentación? Si es así, ignore mi comentario. Parece falso que la API tenga una función que diga writeByte, pero en realidad escribe un int.
sotrh
1
@sotrh que es una copia y pega de un código fuente. Abra la fuente android.os.Parcel y compruébelo usted mismo.
Yaroslav Mytkalyk
66

También puede hacer uso del método writeValue . En mi opinión, esa es la solución más sencilla.

dst.writeValue( myBool );

Luego, puede recuperarlo fácilmente con un elenco simple para Boolean:

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

Bajo el capó, Android Framework lo manejará como un número entero:

writeInt( (Boolean) v ? 1 : 0 );
Taig
fuente
fuente de Android que muestra la parte "debajo del capó" (l. 1219). Aunque un poco menos eficiente (debido a la llamada al método y al conmutador), este método se lee un poco más directo.
desseim
66
El código tal como está escrito aquí no se compilará. readValue requiere un cargador de clases pero no es necesario para los booleanos. Debería leer "boolean myBool = (Boolean) source.readValue (null);" Revisores que no tienen idea de lo que están haciendo y rechazaron mi edición de esta respuesta: @hemang, jeeped, DavidRR.
miguel
1
@miguel Eso es cierto, lo arreglé :)
Taig
15

declaras así

 private boolean isSelectionRight;

escribir

 out.writeInt(isSelectionRight ? 1 : 0);

leer

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

El tipo booleano debe convertirse en algo que Parcel admita y para que podamos convertirlo a int.

Shaista Naaz
fuente
Esto provoca un error, tipos incompatibles, booleano requerido encontrado int?
Paul Okeke
12

AndroidStudio (usando 2.3 atm), después de implementar Parcelable en su clase, simplemente puede mantener el puntero del mouse sobre el nombre de su clase y le pide que agregue la implementación parcelable:

ingrese la descripción de la imagen aquí

A partir de los cuatro campos, genera lo siguiente:

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
fuente
Esto es útil :)
Dino Tw
8

Normalmente los tengo en una matriz y llamo writeBooleanArrayyreadBooleanArray

Si es un booleano único que necesita empacar, puede hacer esto:

parcel.writeBooleanArray(new boolean[] {myBool});
Geobits
fuente
¿Alguna vez ha tenido problemas cuando necesita parcelar algunos booleanos? ¿Podrías ayudarme>? stackoverflow.com/questions/13463727/… . Gracias.
Roger Alien el
8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read
Meghna
fuente
5

Le sugerí la forma más fácil de implementar Parcelable si está utilizando Android Studio.

Simplemente vaya a Archivo-> Configuración-> Complementos-> Examinar repositorio y busque parcelable. Ver imagen

ingrese la descripción de la imagen aquí Creará automáticamente Parcelable.

Y hay un sitio web también para hacer esto. http://www.parcelabler.com/

Zar E Ahmer
fuente
4

Implementación corta y simple en Kotlin , con soporte anulable:

Agregar métodos a la parcela

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

Y úsalo:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false
Pavel Shorokhov
fuente
@AliKazi no puede hacer esto en una declaración de línea en Java con soporte de tipos opcionales. Debe persistir 3 estados. Creo que te olvidas de nulo.
Pavel Shorokhov
@ comm1x, al IDE no le gusta esta solución. `No se puede acceder a" readBoolean "antes de que se haya llamado al constructor de superclase.
Adam Hurwitz
@ comm1x Resolví el problema. Para trabajar, los métodos agregados deben estar dentro del objeto complementario
Adam Hurwitz
3

Puede empaquetar sus valores booleanos en un byte utilizando enmascaramiento y desplazamiento. Esa sería la forma más eficiente de hacerlo y probablemente sea lo que esperarían que hicieras.

fleetway76
fuente
+1. Es cierto que guardar el valor en un byte sería más eficiente. ¿Te importaría editar mi pregunta para representar tu idea?
Octavian A. Damiean
Puedes, pero lo que has escrito no es realmente lo que quise decir. Funcionará pero no es el más eficiente. Puede empaquetar 8 booleanos en un byte usando máscaras y álgebra booleana
Fleetway76
En la mayoría de los casos, estoy de acuerdo con usted, sin embargo, tengo casos que se repiten de vez en cuando, donde necesito tres estados con los que trabajará Boolean. Tal como una pregunta opcional sí / no. Necesito el nulo para saber si el booleano se ha especificado explícitamente o no.
Chad Gorshing
No hay ninguna razón con el byte más int, ya que de la Parcela writeByte()método llama directawriteInt()
Yaroslav Mytkalyk
3

Es difícil identificar la verdadera pregunta aquí. Supongo que es cómo lidiar con los booleanos al implementar la Parcelableinterfaz.

Algunos atributos de MyObject son booleanos, pero Parcel no tiene ningún método read / writeBoolean.

Deberá almacenar el valor como una cadena o como un byte. Si elige una cadena, deberá usar el método estático de la Stringclase llamada valueOf()para analizar el valor booleano. No es tan efectivo como guardarlo en un byte difícil.

String.valueOf(theBoolean);

Si elige un byte, deberá implementar una lógica de conversión usted mismo.

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

Al desarmar el Parcelobjeto, debe hacerse cargo de la conversión al tipo original.

Octavian A. Damiean
fuente
No hay absolutamente ninguna razón para usar String. No hay ninguna razón para usar byte sobre int, ya que el writeByte()método Parcel llama directamente writeInt(). La lógica de conversión es demasiado detallada. Just do writeInt(boolean ? 1 : 0)andboolean = readInt() != 0
Yaroslav Mytkalyk
1

Esta pregunta ya ha sido respondida perfectamente por otras personas, si quieres hacerlo por tu cuenta.

Si prefiere encapsular u ocultar la mayor parte del código de parcelación de bajo nivel, puede considerar usar parte del código que escribí hace algún tiempo para simplificar el manejo de las parcelables.

Escribir en un paquete es tan fácil como:

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

donde color es una enumeración e isDriving es un booleano, por ejemplo.

Leer desde un paquete tampoco es mucho más difícil:

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

Solo eche un vistazo al "ParceldroidExample" que agregué al proyecto.

Finalmente, también mantiene el inicializador CREATOR corto:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);
Michael Geier
fuente
Gracias por .class.getClassLoader().
CoolMind
0

Hay muchos ejemplos en las fuentes de Android (AOSP). Por ejemplo, la PackageInfoclase tiene un miembro booleano requiredForAllUsersy se serializa de la siguiente manera:

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

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