¿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?


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

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

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.


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

...

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

¿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

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/


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

@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.


+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.


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

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;
    ...
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.