-
Notifications
You must be signed in to change notification settings - Fork 29
Java Usage
Important: all information in this on this page is only relevant to PaperParcel 1.x. For information on the latest version of PaperParcel, visit http://grandstaish.github.io/paperparcel/
PaperParcel works by building a Parcelable
wrapper for each class annotated with @PaperParcel
, e.g.
@PaperParcel
public final class Example {
private final int test;
public Example(int test) {
this.test = test;
}
public int getTest() {
return test;
}
}
This example generates a class named ExampleParcel
(the name is always in the format of {ClassName}Parcel
) which is Parcelable
and has the code to read and write an Example
object to and from a Parcel
. ExampleParcel
has a public constructor that takes in an Example
instance and has a public member variable named data
in which you can retrieve your data class from later. The usage for this is simple, just "wrap" your instance in the generated wrapper class and pass it through an Intent
or Bundle
like so:
Example example = new Example(42);
savedInstanceState.putParcelable("example", new ExampleParcel(example));
Then extract it later:
Example example = null
if (savedInstanceState != null) {
ExampleParcel exampleWrapper = savedInstanceState.getParcelable<ExampleParcel>("example");
example = exampleWrapper.data;
}
// TODO: update
PaperParcel makes the following assumptions about an annotated classes:
- The primary constructor must have public or default visibility
- The annotated class' member variable names must equal the primary constructor parameter names (ordering does not matter)
- The number of member variables should equal the number of arguments in the primary constructor. Static and transient member variables are not included in this count.
- For each member variable, either the member variable must be public (or default) or its accessor method must be named
x()
,isX()
,getX()
, wherex
is the member variable's name. Alternatively, the member variable can be annotated with@AccessorName
to specify what the actual accessor name is. Additionally, the accessor method must have no parameters.
Rather than needing to use the generated wrappers directly, it may be preferable to use the convenience class PaperParcels
to wrap/unwrap your objects instead.
Simply wrap like so:
Example example = new Example(42);
savedInstanceState.putParcelable("example", PaperParcels.wrap(example));
And extract using:
Example example = null;
if (savedInstanceState != null) {
TypedParcelable<Example> exampleWrapper = savedInstanceState.getParcelable("example");
example = PaperParcels.unwrap(exampleWrapper);
}
When working with wrapper APIs, like described above, it can make it tricky to work with code that you don't control because the receiving code won't know how to unwrap it. Hence making your model classes implement Parcelable
themselves is the preferred technique. Luckily, PaperParcel makes this easy using the PaperParcelable class found in the paperparcel-java7 module (PaperParcelable
is defined as an interface with default methods in paperparcel-java8 if your app targets Android N+).
PaperParcelable
can be used to make your data classes Parcelable
like so:
@PaperParcel
public final class Example extends PaperParcelable {
public static final PaperParcelable.Creator<Example> CREATOR
= new PaperParcelable.Creator<>(Example.class);
private final int test;
public Example(int test) {
this.test = test;
}
public int getTest() {
return test;
}
}
Note that the CREATOR
field is boilerplate code and is a great candidate for a Live Template.
PaperParcelable
uses the aforementioned PaperParcels
class to do the wrapping and unwrapping internally, so make sure you don't forget the @PaperParcel
annotation on your data class because it'll require that there is a generated wrapper at runtime.
If you can't extend PaperParcelable
, it's not required. Just implement Parcelable
instead, and copy implementation for writeToParcel
and describeContents
(they're both 1-liners).
PaperParcel allows you to use other @PaperParcel
classes as properties without them being Parcelable
themselves, e.g.:
// This class is Parcelable as it is going to be passed directly to
// an Intent or Bundle without using the wrapping APIs in the calling
// and receiving code.
@PaperParcel
public final class Person extends PaperParcelable {
public static final PaperParcelable.Creator<Person> CREATOR
= new PaperParcelable.Creator<>(Person.class);
long id;
String name;
ContactInfo contactInfo;
public Person(long id, String name, ContactInfo contactInfo) {
this.id = id;
this.name = name;
this.contactInfo = contactInfo;
}
}
// This class isn't Parcelable, but PaperParcel will use the generated
// wrapper for this class when parcelling Person
@PaperParcel
public final class class ContactInfo {
String phoneNumber;
String address;
public ContactInfo(String phoneNumber, String address) {
this.phoneNumber = phoneNumber;
this.address = address;
}
}
This is encouraged to help reduce boilerplate code.
If your model class has a public static final
instance of itself named INSTANCE
, then PaperParcel will just use this object and won't bother parcelling/unparcelling anything, e.g.:
@PaperParcel
public final class Example {
public static final Example INSTANCE = new Example();
private final int test = 42;
private Example() {
}
}
This applies for TypeAdapter
s too