-
Notifications
You must be signed in to change notification settings - Fork 29
Kotlin 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
data class Example(
val test: Int
)
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:
val example = Example(42)
savedInstanceState.putParcelable("example", ExampleParcel(example))
Then extract it later:
var example: Example? = null
savedInstanceState?.let {
example = it.getParcelable<ExampleParcel>("example").data
}
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:
val example = Example(42)
savedInstanceState.putParcelable("example", PaperParcels.wrap(example))
And extract using:
var example: Example? = null
savedInstanceState?.let {
example = PaperParcels.unwrap(it.getParcelable<TypedParcelable<Example>>("example"))
}
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 data classes implement Parcelable
themselves is the preferred technique. Luckily, PaperParcel makes this easy using the PaperParcelable interface found in the paperparcel-kotlin module.
PaperParcelable
can be used to make your data classes Parcelable
like so:
@PaperParcel
data class Example(
val test: Int,
...
) : PaperParcelable {
companion object {
@JvmField val CREATOR = PaperParcelable.Creator(Example::class.java)
}
}
Note that the CREATOR
field is boilerplate code and is a great candidate for a Live Template. I wrote a quick tutorial in the wiki to help set it up.
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.
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
data class Person(
val id: Long,
val name: String,
val contactInfo: ContactInfo
) : PaperParcelable {
companion object {
@JvmField val CREATOR = PaperParcelable.Creator(Person::class.java)
}
}
// This class isn't Parcelable, but PaperParcel will use the generated
// wrapper for this class when parcelling Person
@PaperParcel
data class ContactInfo(
val phoneNumber: String,
val address: String
)
This is encouraged to help reduce boilerplate code.
Kotlin object
s are supported, as well as data classes. The API is no different, e.g.:
To generate a wrapper:
@PaperParcel
object Example
Or to make it Parcelable
itself:
@PaperParcel
object Example : PaperParcelable {
@JvmField val CREATOR = PaperParcelable.Creator(Example::class.java)
}
Additionally, TypeAdapter
s can be object
s too:
@DefaultAdapter
object DateTypeAdapter : TypeAdapter<Date> {
override fun writeToParcel(value: Date, outParcel: Parcel, flags: Int) {
outParcel.writeLong(value.time)
}
override fun readFromParcel(inParcel: Parcel): Date {
return Date(inParcel.readLong())
}
}
The example apps are currently quite simplistic. For a more real-world example, see here
If you add additional (non-constructor) properties to your data class, ensure to make them transient (via @Transient
). This is to work around a bug in kapt and won't be required once the bug has been fixed. E.g.:
@PaperParcel
data class Example(
val test: Int
) : PaperParcelable {
...
@delegate:Transient val somethingElse by lazy { ... }
}