¿Tiene alguna pregunta? Pregúntelo en StackOverflow.
¿Encontraste un problema? Por favor repórtelo.
En Android, Parcelables son una excelente manera de serializar objetos Java entre contextos. En comparación con la serialización tradicional, Parcelables requiere aproximadamente 10 veces menos tiempo para serializar y deserializar. Sin embargo, Parcelables tiene un defecto importante. Los parcelables contienen una tonelada de código repetitivo. Para implementar un Parcelable, debe reflejar los métodos writeToParcel()
y createFromParcel()
de manera que lean y escriban en el Parcel en el mismo orden. Además, un Parcelable debe definir un public static final Parcelable.Creator CREATOR
para que la infraestructura de Android pueda aprovechar el código de serialización.
Parceler es una biblioteca de generación de código que genera el código fuente repetitivo de Android Parcelable. Ya no es necesario implementar la interfaz Parcelable, writeToParcel()
o createFromParcel()
o el public static final CREATOR
. Simplemente anota un POJO con @Parcel
y Parceler hace el resto. Debido a que Parceler utiliza el procesador de anotaciones Java JSR-269, no es necesario ejecutar una herramienta manualmente para generar el código Parcelable. Simplemente anota tu Java Bean, compila y listo. De forma predeterminada, Parceler serializará los campos de su instancia directamente:
@ Parcel
public class Example {
String name ;
int age ;
public Example () {}
public Example ( int age , String name ) {
this . age = age ;
this . name = name ;
}
public String getName () { return name ; }
public int getAge () { return age ; }
}
Tenga cuidado de no utilizar campos privados cuando utilice la estrategia de serialización de campos predeterminada, ya que incurrirá en una penalización de rendimiento debido a la reflexión.
Para utilizar el código generado, puede hacer referencia a la clase generada directamente o mediante la clase de utilidad Parcels
:
Parcelable wrapped = Parcels . wrap ( new Example ( "Andy" , 42 ));
Para eliminar la referencia a @Parcel
, simplemente llame al método Parcels.unwrap()
:
Example example = Parcels . unwrap ( wrapped );
example . getName (); // Andy
example . getAge (); // 42
Por supuesto, el Parcelable
empaquetado se puede agregar a un paquete de Android para transferirlo de una actividad a otra:
Bundle bundle = new Bundle ();
bundle . putParcelable ( "example" , Parcels . wrap ( example ));
Y desreferenciado en el método onCreate()
:
Example example = Parcels . unwrap ( getIntent (). getParcelableExtra ( "example" ));
Esta técnica de envolver y desenvolver combina bien con el patrón Intent Factory. Además, Parceler es compatible con las siguientes bibliotecas:
Transfuse: permite utilizar beans anotados con @Parcel
con la inyección @Extra
.
FragmentArgs: utiliza el adaptador ParcelerArgsBundler
para envolver y desenvolver beans anotados @Parcel
con parámetros de fragmento.
Dart: detecta automáticamente los beans anotados @Parcel
y los desenvuelve automáticamente cuando se usa @InjectExtra
.
AndroidAnnotations: detecta automáticamente los beans anotados @Parcel
y los envuelve/desenvuelve automáticamente cuando se utilizan @Extra
, @FragmentArg
, @InstanceState
y otras anotaciones relacionadas con Bundle
.
ActivityStarter: admite de forma nativa objetos Parceler como argumentos para actividades, fragmentos, servicios, etc.
Remoter: admite de forma nativa objetos Parceler como argumentos en interfaces @Remoter.
Solo se puede utilizar un número selecto de tipos como atributos de una clase @Parcel
. La siguiente lista incluye los tipos asignados:
byte
double
float
int
long
char
boolean
String
IBinder
Bundle
SparseArray
de cualquiera de los tipos mapeados*
SparseBooleanArray
ObservableField
List
, ArrayList
y LinkedList
de cualquiera de los tipos mapeados*
Map
, HashMap
, LinkedHashMap
, SortedMap
y TreeMap
de cualquiera de los tipos mapeados*
Set
, HashSet
, SortedSet
, TreeSet
, LinkedHashSet
de cualquiera de los tipos asignados*
Parcelable
Serializable
Matriz de cualquiera de los tipos mapeados
Cualquier otra clase anotada con @Parcel
*El paquete generará un error si el parámetro genérico no está asignado.
Parceler también admite directamente cualquiera de los tipos anteriores. Esto es especialmente útil cuando se trata de colecciones de clases anotadas con @Parcel
:
Parcelable listParcelable = Parcels . wrap ( new ArrayList < Example >());
Parcelable mapParcelable = Parcels . wrap ( new HashMap < String , Example >());
Tenga en cuenta que Parceler no desencapsula las jerarquías de herencia, por lo que cualquier campo polimórfico se desencapsulará como instancias de la clase base. Esto se debe a que Parceler opta por el rendimiento en lugar de verificar .getClass()
para cada dato.
@ Parcel
public class Example {
public Parent p ;
@ ParcelConstructor Example ( Parent p ) { this . p = p ; }
}
@ Parcel public class Parent {}
@ Parcel public class Child extends Parent {}
Example example = new Example ( new Child ());
System . out . println ( "%b" , example . p instanceof Child ); // true
example = Parcels . unwrap ( Parcels . wrap ( example ));
System . out . println ( "%b" , example . p instanceof Child ); // false
Consulte la sección Serialización personalizada para ver un ejemplo de cómo trabajar con campos polimórficos.
Parceler ofrece varias opciones sobre cómo serializar y deserializar un objeto además de la serialización basada en campos que se ve arriba.
Parceler se puede configurar para serializar utilizando métodos getter y setter y un constructor no vacío. Además, los campos, métodos y parámetros del constructor se pueden asociar mediante la anotación @ParcelProperty
. Esto admite una serie de estrategias de beans, incluida la inmutabilidad y los beans getter/setter tradicionales.
Para configurar la serialización del método predeterminado, simplemente configure la anotación @Parcel
con Serialization.BEAN
:
@ Parcel ( Serialization . BEAN )
public class Example {
private String name ;
private int age ;
private boolean enabled ;
public String getName () { return name ; }
public void setName ( String name ) { this . name = name ; }
public int getAge () { return age ; }
public void setAge ( int age ) { this . age = age ; }
public boolean isEnabled () { return enabled ; }
public void setEnabled ( boolean enabled ) { this . enabled = enabled ; }
}
Para utilizar un constructor con serialización, anote el constructor deseado con la anotación @ParcelConstructor
:
@ Parcel ( Serialization . BEAN )
public class Example {
private final String name ;
private final int age ;
private boolean enabled ;
@ ParcelConstructor
public Example ( int age , String name , boolean enabled ) {
this . age = age ;
this . name = name ;
this . enabled = enabled ;
}
public String getName () { return name ; }
public int getAge () { return age ; }
public boolean isEnabled () { return enabled ; }
}
Si hay un constructor vacío, Parceler usará ese constructor a menos que se anote otro constructor.
También puede mezclar y combinar técnicas de serialización utilizando la anotación @ParcelProperty
. En el siguiente ejemplo, firstName
y lastName
se escriben en el bean usando el constructor, mientras que firstName
se lee del bean usando el campo y lastName
se lee usando el método getLastName()
. Los parámetros firstName
y lastName
están coordinados por los nombres de parámetro "first"
y "last"
respectivamente.
@ Parcel
public class Example {
@ ParcelProperty ( "first" )
String firstName ;
String lastName ;
@ ParcelConstructor
public Example ( @ ParcelProperty ( "first" ) String firstName , @ ParcelProperty ( "last" ) String lastName ){
this . firstName = firstName ;
this . lastName = lastName ;
}
public String getFirstName () { return firstName ; }
@ ParcelProperty ( "last" )
public String getLastName () { return lastName ; }
}
Para los atributos que no deben serializarse con Parceler, @Transient
puede anotar el campo de atributo, el captador o el definidor.
Parceler admite muchos estilos diferentes centrados en POJO. Esto permite que las clases anotadas @Parcel
se utilicen con otras bibliotecas basadas en POJO, incluidas las siguientes:
GSON
Reino
Armario
XML sencillo
DBFlow
Como alternativa al uso directo de un constructor, Parceler admite el uso de una fábrica estática anotada para crear una instancia de la clase dada. Este estilo es compatible con la biblioteca de generación de código/procesador de anotaciones AutoValue de Google para generar beans inmutables. Parceler interactúa con AutoValue a través de la anotación @ParcelFactory
, que asigna un método de fábrica estático a la serialización @Parcel
anotada:
@ AutoValue
@ Parcel
public abstract class AutoValueParcel {
@ ParcelProperty ( "value" ) public abstract String value ();
@ ParcelFactory
public static AutoValueParcel create ( String value ) {
return new AutoValue_AutoValueParcel ( value );
}
}
AutoValue genera una clase diferente a la @Parcel
anotada, por lo tanto, debe especificar qué clase debe compilar Parceler en la clase de utilidad Parcels
:
Parcelable wrappedAutoValue = Parcels . wrap ( AutoValueParcel . class , AutoValueParcel . create ( "example" ));
Y para deserializar:
AutoValueParcel autoValueParcel = Parcels . unwrap ( wrappedAutoValue );
@Parcel
incluye un parámetro opcional para incluir un ParcelConverter
serializador manual para el caso en que sea necesaria una serialización especial. Esto proporciona una opción aún más limpia para usar clases Parcelable que implementarlas manualmente.
El siguiente código demuestra el uso de ParcelConverter
para desencapsular la jerarquía de herencia durante la deserialización.
@ Parcel
public class Item {
@ ParcelPropertyConverter ( ItemListParcelConverter . class )
public List < Item > itemList ;
}
@ Parcel public class SubItem1 extends Item {}
@ Parcel public class SubItem2 extends Item {}
public class ItemListParcelConverter implements ParcelConverter < List < Item >> {
@ Override
public void toParcel ( List < Item > input , Parcel parcel ) {
if ( input == null ) {
parcel . writeInt (- 1 );
}
else {
parcel . writeInt ( input . size ());
for ( Item item : input ) {
parcel . writeParcelable ( Parcels . wrap ( item ), 0 );
}
}
}
@ Override
public List < Item > fromParcel ( Parcel parcel ) {
int size = parcel . readInt ();
if ( size < 0 ) return null ;
List < Item > items = new ArrayList < Item >();
for ( int i = 0 ; i < size ; ++ i ) {
items . add (( Item ) Parcels . unwrap ( parcel . readParcelable ( Item . class . getClassLoader ())));
}
return items ;
}
}
Parceler también incluye una serie de clases base para facilitar la conversión de la colección, ubicadas en el paquete org.parceler.converter
de la API. Estas clases base se encargan de una variedad de trabajos difíciles o detallados relacionados con colecciones, incluidas comprobaciones nulas e iteraciones de colecciones. Por ejemplo, el ParcelConverter
anterior podría escribirse usando `ArrayListParcelConverter':
public class ItemListParcelConverter extends ArrayListParcelConverter < Item > {
@ Override
public void itemToParcel ( Item item , Parcel parcel ) {
parcel . writeParcelable ( Parcels . wrap ( item ), 0 );
}
@ Override
public Item itemFromParcel ( Parcel parcel ) {
return Parcels . unwrap ( parcel . readParcelable ( Item . class . getClassLoader ()));
}
}
Para las clases cuya fuente Java correspondiente no está disponible, se puede incluir la clase como Parcel utilizando la anotación @ParcelClass
. Esta anotación puede declararse en cualquier lugar de la fuente compilada que sea conveniente. Por ejemplo, se podría incluir @ParcelClass
junto con la aplicación de Android:
@ ParcelClass ( LibraryParcel . class )
public class AndroidApplication extends Application {
//...
}
Se pueden declarar varias anotaciones @ParcelClass
utilizando la anotación @ParcelClasses
.
Además, las clases a las que hace referencia @ParcelClass
se pueden configurar utilizando la anotación @Parcel
. Esto permite la configuración de serialización a través de cualquier parámetro disponible en la anotación @Parcel
incluyendo la técnica de serialización o clases a analizar.
Una técnica útil es la capacidad de definir convertidores personalizados globales para un tipo:
@ ParcelClass (
value = LibraryParcel . class ,
annotation = @ Parcel ( converter = LibraryParcelConverter . class ))
class SomeClass {}
Esto permite un control detallado sobre una clase que no está disponible para modificación directa.
Es una práctica común que algunas bibliotecas requieran un bean para extender una clase base. Aunque no es el caso más óptimo, Parceler admite esta práctica al permitir la configuración de qué clases en la jerarquía de herencia analizar mediante el parámetro de análisis:
@ Parcel ( analyze = { One . class , Three . class })
class One extends Two {}
class Two extends Three {}
class Three extends BaseClass {}
En este ejemplo, solo se serializarán los campos de las clases One
y Three
, evitando los parámetros de clase BaseClass
y Two
.
La clase de utilidad Parcels busca la clase dada para empaquetarla por clase. Por razones de rendimiento, esto ignora la herencia, tanto de las clases base como de las superclases. Hay dos soluciones a este problema. Primero, se pueden especificar tipos adicionales para asociar al tipo dado mediante el parámetro implementations
:
class ExampleProxy extends Example {}
@ Parcel ( implementations = { ExampleProxy . class })
class Example {}
ExampleProxy proxy = new ExampleProxy ();
Parcels . wrap ( proxy ); // ExampleProxy will be serialized as a Example
En segundo lugar, también se puede especificar el tipo de clase cuando se utiliza el método Parcels.wrap()
:
ExampleProxy proxy = new ExampleProxy ();
Parcels . wrap ( Example . class , proxy );
Para configurar Proguard, agregue las siguientes líneas a su archivo de configuración de proguard. Estos mantendrán los archivos relacionados con la clase de utilidad Parcels
y la instancia Parcelable
CREATOR
: er
# Biblioteca de parcelas -mantener interfaz org.parceler.Parcel -mantener @org.parceler.Clase de parcela * { *; } -mantener clase **$$Parcelable { *; }
Puede descargar Parceler como una dependencia de Maven:
< dependency >
< groupId >org.parceler</ groupId >
< artifactId >parceler</ artifactId >
< version >1.1.12</ version >
< scope >provided</ scope >
</ dependency >
< dependency >
< groupId >org.parceler</ groupId >
< artifactId >parceler-api</ artifactId >
< version >1.1.12</ version >
</ dependency >
o Gradle:
implementation ' org.parceler:parceler-api:1.1.12 '
annotationProcessor ' org.parceler:parceler:1.1.12 '
O desde Maven Central.
Copyright 2011-2015 John Ericksen Licenciado bajo la Licencia Apache, Versión 2.0 (la "Licencia"); no puede utilizar este archivo excepto de conformidad con la Licencia. Puede obtener una copia de la Licencia en http://www.apache.org/licenses/LICENSE-2.0 A menos que lo exija la ley aplicable o se acuerde por escrito, el software distribuido bajo la Licencia se distribuye "TAL CUAL", SIN GARANTÍAS NI CONDICIONES DE NINGÚN TIPO, ya sean expresas o implícitas. Consulte la Licencia para conocer el idioma específico que rige los permisos y limitaciones bajo la Licencia.