Tem alguma pergunta? Pergunte no StackOverflow.
Encontrou um problema? Por favor, denuncie.
No Android, Parcelables são uma ótima maneira de serializar objetos Java entre contextos. Em comparação com a serialização tradicional, os Parcelables levam cerca de 10 vezes menos tempo para serializar e desserializar. Há uma grande falha com Parcelables, no entanto. Parcelables contêm uma tonelada de código padrão. Para implementar um Parcelable, você deve espelhar os métodos writeToParcel()
e createFromParcel()
de forma que eles leiam e gravem no Parcel na mesma ordem. Além disso, um Parcelable deve definir um public static final Parcelable.Creator CREATOR
para que a infraestrutura Android possa aproveitar o código de serialização.
Parceler é uma biblioteca de geração de código que gera o código-fonte padrão do Android Parcelable. Você não precisa mais implementar a interface Parcelable, o writeToParcel()
ou createFromParcel()
ou o public static final CREATOR
. Você simplesmente anota um POJO com @Parcel
e o Parceler faz o resto. Como o Parceler usa o processador de anotação Java JSR-269, não há necessidade de executar uma ferramenta manualmente para gerar o código Parcelable. Basta anotar seu Java Bean, compilar e pronto. Por padrão, o Parceler serializará os campos da sua instância diretamente:
@ 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 ; }
}
Tenha cuidado para não usar campos privados ao usar a estratégia de serialização de campo padrão, pois isso incorrerá em uma penalidade de desempenho devido à reflexão.
Para usar o código gerado, você pode referenciar a classe gerada diretamente ou através da classe utilitária Parcels
:
Parcelable wrapped = Parcels . wrap ( new Example ( "Andy" , 42 ));
Para desreferenciar o @Parcel
, basta chamar o método Parcels.unwrap()
:
Example example = Parcels . unwrap ( wrapped );
example . getName (); // Andy
example . getAge (); // 42
Claro, o Parcelable
empacotado pode ser adicionado a um Android Bundle para transferir de atividade para atividade:
Bundle bundle = new Bundle ();
bundle . putParcelable ( "example" , Parcels . wrap ( example ));
E desreferenciado no método onCreate()
:
Example example = Parcels . unwrap ( getIntent (). getParcelableExtra ( "example" ));
Essa técnica de embrulhar e desembrulhar funciona bem com o padrão Intent Factory. Além disso, o Parceler é suportado pelas seguintes bibliotecas:
Transfuse - Permite que beans anotados @Parcel
sejam usados com a injeção @Extra
.
FragmentArgs - Usa o adaptador ParcelerArgsBundler
para agrupar e desembrulhar beans anotados @Parcel
com parâmetros de fragmento.
Dart - detecta automaticamente os beans anotados @Parcel
e os desembrulha automaticamente ao usar @InjectExtra
.
AndroidAnnotations - detecta automaticamente beans anotados @Parcel
e os agrupa/desembrulha automaticamente ao usar @Extra
, @FragmentArg
, @InstanceState
e outras anotações relacionadas Bundle
.
ActivityStarter - Suporta nativamente objetos Parceler como argumentos para Atividades, Fragmentos, Serviços, etc.
Remoter - Suporta nativamente objetos Parceler como argumentos em interfaces @Remoter.
Apenas um número selecionado de tipos pode ser usado como atributos de uma classe @Parcel
. A lista a seguir inclui os tipos mapeados:
byte
double
float
int
long
char
boolean
String
IBinder
Bundle
SparseArray
de qualquer um dos tipos mapeados*
SparseBooleanArray
ObservableField
List
, ArrayList
e LinkedList
de qualquer um dos tipos mapeados*
Map
, HashMap
, LinkedHashMap
, SortedMap
e TreeMap
de qualquer um dos tipos mapeados*
Set
, HashSet
, SortedSet
, TreeSet
, LinkedHashSet
de qualquer um dos tipos mapeados*
Parcelable
Serializable
Matriz de qualquer um dos tipos mapeados
Qualquer outra classe anotada com @Parcel
*O pacote apresentará erro se o parâmetro genérico não for mapeado.
O Parceler também oferece suporte direto a qualquer um dos tipos acima. Isto é especialmente útil ao lidar com coleções de classes anotadas com @Parcel
:
Parcelable listParcelable = Parcels . wrap ( new ArrayList < Example >());
Parcelable mapParcelable = Parcels . wrap ( new HashMap < String , Example >());
Observe que o Parceler não desembrulha hierarquias de herança, portanto, quaisquer campos polimórficos serão desembrulhados como instâncias da classe base. Isso ocorre porque o Parceler opta pelo desempenho em vez de verificar .getClass()
para cada dado.
@ 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 a seção Serialização personalizada para obter um exemplo de como trabalhar com campos polimórficos.
O Parceler oferece várias opções de como serializar e desserializar um objeto, além da serialização baseada em campo vista acima.
O Parceler pode ser configurado para serializar usando métodos getter e setter e um construtor não vazio. Além disso, campos, métodos e parâmetros construtores podem ser associados usando a anotação @ParcelProperty
. Isso suporta uma série de estratégias de bean, incluindo imutabilidade e beans getter/setter tradicionais.
Para configurar a serialização do método padrão, basta configurar a anotação @Parcel
com 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 usar um construtor com serialização, anote o construtor desejado com a anotação @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 ; }
}
Se um construtor vazio estiver presente, o Parceler usará esse construtor, a menos que outro construtor seja anotado.
Você também pode misturar e combinar técnicas de serialização usando a anotação @ParcelProperty
. No exemplo a seguir, firstName
e lastName
são gravados no bean usando o construtor enquanto firstName
é lido do bean usando o campo e lastName
é lido usando o método getLastName()
. Os parâmetros firstName
e lastName
são coordenados pelos nomes dos parâmetros "first"
e "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 atributos que não devem ser serializados com Parceler, o campo de atributo, getter ou setter pode ser anotado por @Transient
.
O Parceler oferece suporte a muitos estilos diferentes centrados no POJO. Isso permite que classes anotadas @Parcel
sejam usadas com outras bibliotecas baseadas em POJO, incluindo as seguintes:
GSON
Reino
Armário
XML simples
DBFlow
Como alternativa ao uso direto de um construtor, o Parceler oferece suporte ao uso de um Static Factory anotado para construir uma instância de uma determinada classe. Este estilo suporta o processador de anotação AutoValue/biblioteca de geração de código do Google para gerar beans imutáveis. O Parceler faz interface com o AutoValue por meio da anotação @ParcelFactory
, que mapeia um método de fábrica estático na serialização @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 gera uma classe diferente da anotada @Parcel
, portanto, você precisa especificar qual classe Parceler deve construir na classe de utilitário Parcels
:
Parcelable wrappedAutoValue = Parcels . wrap ( AutoValueParcel . class , AutoValueParcel . create ( "example" ));
E para desserializar:
AutoValueParcel autoValueParcel = Parcels . unwrap ( wrappedAutoValue );
@Parcel
inclui um parâmetro opcional para incluir um serializador manual ParcelConverter
para o caso onde uma serialização especial é necessária. Isso fornece uma opção ainda mais limpa para usar classes Parcelable do que implementá-las manualmente.
O código a seguir demonstra o uso de um ParcelConverter
para desempacotar a hierarquia de herança durante a desserialização.
@ 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 ;
}
}
O Parceler também vem com uma série de classes base para facilitar a conversão da coleção, localizadas no pacote org.parceler.converter
da API. Essas classes base cuidam de uma variedade de trabalhos difíceis ou detalhados que lidam com coleções, incluindo verificações de nulos e iteração de coleções. Por exemplo, o ParcelConverter
acima poderia ser escrito 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 classes cuja fonte Java correspondente não está disponível, pode-se incluir a classe como Parcel usando a anotação @ParcelClass
. Esta anotação pode ser declarada em qualquer lugar conveniente na fonte compilada. Por exemplo, pode-se incluir @ParcelClass
junto com o aplicativo Android:
@ ParcelClass ( LibraryParcel . class )
public class AndroidApplication extends Application {
//...
}
Múltiplas anotações @ParcelClass
podem ser declaradas usando a anotação @ParcelClasses
.
Além disso, as classes referenciadas por @ParcelClass
podem ser configuradas usando a anotação @Parcel
. Isto permite a configuração da serialização através de qualquer parâmetro disponível na anotação @Parcel
incluindo a técnica de serialização ou classes a serem analisadas.
Uma técnica útil é a capacidade de definir conversores personalizados globais para um tipo:
@ ParcelClass (
value = LibraryParcel . class ,
annotation = @ Parcel ( converter = LibraryParcelConverter . class ))
class SomeClass {}
Isso permite um controle refinado sobre uma classe que não está disponível para modificação direta.
É uma prática comum que algumas bibliotecas exijam um bean para estender uma classe base. Embora não seja o caso mais ideal, o Parceler suporta esta prática permitindo a configuração de quais classes na hierarquia de herança analisar através do parâmetro analyze:
@ Parcel ( analyze = { One . class , Three . class })
class One extends Two {}
class Two extends Three {}
class Three extends BaseClass {}
Neste exemplo, apenas os campos das classes One
e Three
serão serializados, evitando os parâmetros das classes BaseClass
e Two
.
A classe de utilitário Parcels procura a classe fornecida para agrupar por classe. Por razões de desempenho, isso ignora a herança, tanto as classes super quanto as classes base. Existem duas soluções para este problema. Primeiro, pode-se especificar tipos adicionais para associar ao tipo determinado através do 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
Segundo, também é possível especificar o tipo de classe ao usar o método Parcels.wrap()
:
ExampleProxy proxy = new ExampleProxy ();
Parcels . wrap ( Example . class , proxy );
Para configurar o Proguard, adicione as seguintes linhas ao arquivo de configuração do proguard. Eles manterão os arquivos relacionados à classe utilitária Parcels
e à instância Parcelable
CREATOR
: er
# Biblioteca Parceladora -manter interface org.parceler.Parcel -keep @org.parceler.Parcel classe * { *; } -keep class **$$Parcelável { *; }
Você pode baixar o Parceler como uma dependência do 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 da Maven Central.
Direitos autorais 2011-2015 John Ericksen Licenciado sob a Licença Apache, Versão 2.0 (a "Licença"); você não pode usar este arquivo exceto em conformidade com a Licença. Você pode obter uma cópia da Licença em http://www.apache.org/licenses/LICENSE-2.0 A menos que exigido pela lei aplicável ou acordado por escrito, o software distribuído sob a Licença é distribuído "COMO ESTÁ", SEM GARANTIAS OU CONDIÇÕES DE QUALQUER TIPO, expressas ou implícitas. Consulte a Licença para o idioma específico que rege as permissões e limitações sob a Licença.