Vous avez une question ? Demandez-le sur StackOverflow.
Vous avez trouvé un problème ? Veuillez le signaler.
Sous Android, les Parcelables constituent un excellent moyen de sérialiser des objets Java entre contextes. Par rapport à la sérialisation traditionnelle, les Parcelables prennent environ 10 fois moins de temps à sérialiser et à désérialiser. Il y a cependant un défaut majeur avec Parcelables. Les colisables contiennent une tonne de code passe-partout. Pour implémenter un Parcelable, vous devez mettre en miroir les méthodes writeToParcel()
et createFromParcel()
de telle sorte qu'elles lisent et écrivent dans le Parcel dans le même ordre. En outre, un Parcelable doit définir un public static final Parcelable.Creator CREATOR
pour que l'infrastructure Android puisse exploiter le code de sérialisation.
Parceler est une bibliothèque de génération de code qui génère le code source standard Android Parcelable. Vous n'avez plus besoin d'implémenter l'interface Parcelable, le writeToParcel()
ou createFromParcel()
ou le public static final CREATOR
. Vous annotez simplement un POJO avec @Parcel
et Parceler fait le reste. Étant donné que Parceler utilise le processeur d'annotation Java JSR-269, il n'est pas nécessaire d'exécuter un outil manuellement pour générer le code Parcelable. Annotez simplement votre Java Bean, compilez et vous avez terminé. Par défaut, Parceler sérialisera directement les champs de votre instance :
@ 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 ; }
}
Veillez à ne pas utiliser de champs privés lorsque vous utilisez la stratégie de sérialisation de champs par défaut, car cela entraînerait une pénalité de performances en raison de la réflexion.
Pour utiliser le code généré, vous pouvez référencer la classe générée directement, ou via la classe utilitaire Parcels
:
Parcelable wrapped = Parcels . wrap ( new Example ( "Andy" , 42 ));
Pour déréférencer le @Parcel
, appelez simplement la méthode Parcels.unwrap()
:
Example example = Parcels . unwrap ( wrapped );
example . getName (); // Andy
example . getAge (); // 42
Bien sûr, le Parcelable
enveloppé peut être ajouté à un bundle Android pour être transféré d'une activité à l'autre :
Bundle bundle = new Bundle ();
bundle . putParcelable ( "example" , Parcels . wrap ( example ));
Et déréférencé dans la méthode onCreate()
:
Example example = Parcels . unwrap ( getIntent (). getParcelableExtra ( "example" ));
Cette technique d’emballage et de déballage s’accorde bien avec le modèle Intent Factory. De plus, Parceler est pris en charge par les bibliothèques suivantes :
Transfuse - Permet d'utiliser les beans annotés @Parcel
avec l'injection @Extra
.
FragmentArgs - Utilise l'adaptateur ParcelerArgsBundler
pour envelopper et déballer les beans annotés @Parcel
avec des paramètres de fragment.
Dart - Détecte automatiquement les beans annotés @Parcel
et les déballe automatiquement lors de l'utilisation @InjectExtra
.
AndroidAnnotations - Détecte automatiquement les beans annotés @Parcel
et les enveloppe/déballe automatiquement lors de l'utilisation @Extra
, @FragmentArg
, @InstanceState
et d'autres annotations liées Bundle
.
ActivityStarter - Prend en charge nativement les objets Parceler comme arguments pour les activités, fragments, services, etc.
Remoter - Prend en charge nativement les objets Parceler comme arguments dans les interfaces @Remoter.
Seul un certain nombre de types peuvent être utilisés comme attributs d’une classe @Parcel
. La liste suivante inclut les types mappés :
byte
double
float
int
long
char
boolean
String
IBinder
Bundle
SparseArray
de l'un des types mappés*
SparseBooleanArray
ObservableField
List
, ArrayList
et LinkedList
de l'un des types mappés*
Map
, HashMap
, LinkedHashMap
, SortedMap
et TreeMap
de l'un des types mappés*
Set
, HashSet
, SortedSet
, TreeSet
, LinkedHashSet
de l'un des types mappés*
Parcelable
Serializable
Tableau de l’un des types mappés
Toute autre classe annotée avec @Parcel
*Parcel entraînera une erreur si le paramètre générique n'est pas mappé.
Parceler prend également en charge directement l’un des types ci-dessus. Ceci est particulièrement utile lorsqu'il s'agit de collections de classes annotées avec @Parcel
:
Parcelable listParcelable = Parcels . wrap ( new ArrayList < Example >());
Parcelable mapParcelable = Parcels . wrap ( new HashMap < String , Example >());
Notez que Parceler ne déballe pas les hiérarchies d'héritage, donc tous les champs polymorphes seront déballés en tant qu'instances de la classe de base. En effet, Parceler opte pour les performances plutôt que de vérifier .getClass()
pour chaque élément de données.
@ 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
Reportez-vous à la section Sérialisation personnalisée pour un exemple d'utilisation de champs polymorphes.
Parceler propose plusieurs choix sur la façon de sérialiser et de désérialiser un objet en plus de la sérialisation basée sur les champs vue ci-dessus.
Parceler peut être configuré pour sérialiser à l'aide de méthodes getter et setter et d'un constructeur non vide. De plus, les champs, méthodes et paramètres de constructeur peuvent être associés à l'aide de l'annotation @ParcelProperty
. Cela prend en charge un certain nombre de stratégies de beans, notamment l'immuabilité et les beans getter/setter traditionnels.
Pour configurer la sérialisation de la méthode par défaut, configurez simplement l'annotation @Parcel
avec 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 ; }
}
Pour utiliser un constructeur avec sérialisation, annotez le constructeur souhaité avec l'annotation @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 un constructeur vide est présent, Parceler utilisera ce constructeur à moins qu'un autre constructeur ne soit annoté.
Vous pouvez également mélanger et assortir les techniques de sérialisation à l'aide de l'annotation @ParcelProperty
. Dans l'exemple suivant, firstName
et lastName
sont écrits dans le bean à l'aide du constructeur tandis que firstName
est lu à partir du bean à l'aide du champ et lastName
est lu à l'aide de la méthode getLastName()
. Les paramètres firstName
et lastName
sont respectivement coordonnés par les noms de paramètres "first"
et "last"
.
@ 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 ; }
}
Pour les attributs qui ne doivent pas être sérialisés avec Parceler, le champ d'attribut, getter ou setter peut être annoté par @Transient
.
Parceler prend en charge de nombreux styles différents centrés sur le POJO. Cela permet aux classes annotées @Parcel
d'être utilisées avec d'autres bibliothèques basées sur POJO, notamment les suivantes :
GSON
Royaume
Placard
XML simple
DBFlow
Au lieu d'utiliser directement un constructeur, Parceler prend en charge l'utilisation d'une usine statique annotée pour créer une instance de la classe donnée. Ce style prend en charge le processeur d'annotations AutoValue/la bibliothèque de génération de code de Google pour générer des beans immuables. Parceler s'interface avec AutoValue via l'annotation @ParcelFactory
, qui mappe une méthode de fabrique statique dans la sérialisation @Parcel
annotée :
@ 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 génère une classe différente de celle annotée @Parcel
, vous devez donc spécifier quelle classe Parceler doit créer dans la classe utilitaire Parcels
:
Parcelable wrappedAutoValue = Parcels . wrap ( AutoValueParcel . class , AutoValueParcel . create ( "example" ));
Et pour désérialiser :
AutoValueParcel autoValueParcel = Parcels . unwrap ( wrappedAutoValue );
@Parcel
inclut un paramètre facultatif pour inclure un sérialiseur manuel ParcelConverter
dans le cas où une sérialisation spéciale est nécessaire. Cela fournit une option encore plus propre pour utiliser les classes Parcelable plutôt que de les implémenter manuellement.
Le code suivant montre l'utilisation d'un ParcelConverter
pour déballer la hiérarchie d'héritage pendant la désérialisation.
@ 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 est également fourni avec une série de classes de base pour faciliter la conversion de collection, situées sous le package org.parceler.converter
de l'API. Ces classes de base s'occupent d'une variété de tâches difficiles ou verbeuses traitant des collections, notamment les vérifications nulles et les itérations de collecte. Par exemple, le ParcelConverter
ci-dessus pourrait être écrit en utilisant `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 ()));
}
}
Pour les classes dont la source Java correspondante n'est pas disponible, on peut inclure la classe en tant que Parcel en utilisant l'annotation @ParcelClass
. Cette annotation peut être déclarée n'importe où dans la source compilée qui convient. Par exemple, on pourrait inclure le @ParcelClass
avec l'application Android :
@ ParcelClass ( LibraryParcel . class )
public class AndroidApplication extends Application {
//...
}
Plusieurs annotations @ParcelClass
peuvent être déclarées à l'aide de l'annotation @ParcelClasses
.
De plus, les classes référencées par @ParcelClass
peuvent être configurées à l'aide de l'annotation @Parcel
. Cela permet la configuration de la sérialisation via n'importe quel paramètre disponible sur l'annotation @Parcel
y compris la technique de sérialisation ou les classes à analyser.
Une technique utile est la possibilité de définir des convertisseurs personnalisés globaux pour un type :
@ ParcelClass (
value = LibraryParcel . class ,
annotation = @ Parcel ( converter = LibraryParcelConverter . class ))
class SomeClass {}
Cela permet un contrôle précis sur une classe qui n'est pas disponible pour une modification directe.
Il est courant que certaines bibliothèques exigent qu'un bean étende une classe de base. Bien que ce ne soit pas le cas le plus optimal, Parceler prend en charge cette pratique en permettant la configuration des classes de la hiérarchie d'héritage à analyser via le paramètre analyse :
@ Parcel ( analyze = { One . class , Three . class })
class One extends Two {}
class Two extends Three {}
class Three extends BaseClass {}
Dans cet exemple, seuls les champs des classes One
et Three
seront sérialisés, évitant ainsi les paramètres de classe BaseClass
et Two
.
La classe utilitaire Parcels recherche la classe donnée pour l'encapsuler par classe. Pour des raisons de performances, cela ignore l'héritage, tant des classes super que des classes de base. Il existe deux solutions à ce problème. Tout d'abord, on peut spécifier des types supplémentaires à associer au type donné via le paramètre 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
Deuxièmement, on peut également spécifier le type de classe lors de l'utilisation de la méthode Parcels.wrap()
:
ExampleProxy proxy = new ExampleProxy ();
Parcels . wrap ( Example . class , proxy );
Pour configurer Proguard, ajoutez les lignes suivantes à votre fichier de configuration proguard. Ceux-ci conserveront les fichiers liés à la classe utilitaire Parcels
et à l'instance Parcelable
CREATOR
: euh
# Bibliothèque de coliseurs -conserver l'interface org.parceler.Parcel -garder la classe @org.parceler.Parcel * { *; } -keep classe **$$Parcelable { *; }
Vous pouvez télécharger Parceler en tant que dépendance 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 >
ou Gradle :
implementation ' org.parceler:parceler-api:1.1.12 '
annotationProcessor ' org.parceler:parceler:1.1.12 '
Ou depuis Maven Central.
Copyright 2011-2015 John Ericksen Sous licence Apache, version 2.0 (la « Licence » ); vous ne pouvez pas utiliser ce fichier sauf en conformité avec la licence. Vous pouvez obtenir une copie de la licence à http://www.apache.org/licenses/LICENSE-2.0 Sauf si requis par la loi applicable ou convenu par écrit, le logiciel distribué sous la Licence est distribué sur une BASE « TEL QUEL », SANS GARANTIE NI CONDITIONS D'AUCUNE SORTE, expresses ou implicites. Consultez la licence pour connaître la langue spécifique régissant les autorisations et limitations en vertu de la licence.