Parcelable
You are discouraged to use the Java serialization framework on the Android platform for performance reasons. Instead, Android comes with its own serialization tool: Parcelable. A Parcelable class requires you to implement the Parcelable
interface and also to fulfill a certain contract as show below.
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable
{
private int age;
private String name;
// Getters and Setters [...]
public User( int age, String name ) {
this.age = age;
this.name = name;
}
protected User( Parcel source ) {
this( source.readInt(), source.readString() )
}
@Override
public int describeContents() { return 0; }
@Override
public void writeToParcel( Parcel destination, int flags ) {
destination.writeInt( age );
destination.writeString( name );
}
// Implemented by contract, if this field is not around you will encounter runtime
// exceptions
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
public User createFromParcel( Parcel source ) { return new User( source ); }
public User[] newArray( int size ) { return new User[size]; }
};
}
A Parcelable class forces you to implement a lot of boilerplate code, but offers great performance as it does not rely on runtime reflection like the default Java serialization framework. But when it comes to Scala on Android there emerges another problem: the Parcelable contract requires a static class member. This is impossible in Scala because there is no support for statics.
Luckily, the Scala compiler checks for the Android Parcelable
interface and treats it in a special way to support Android development. At the end of the day there is just another contract to implement that relies on the class' companion to overcome the lack of statics. Below is a valid Scala implementation of the previous example.
import android.os.{ Parcel, Parcelable }
case class User( age: Int, name: String ) extends Parcelable {
protected this( source: Parcel ) = this( source.readInt(), source.readString() )
override def describeContents() = 0
override def writeToParcel( destination: Parcel, flags: Int ) {
destination.writeInt( age )
destination.writeString( name )
}
}
object User
{
// This is by contract, the CREATOR field must exist for every class that implements
// the Parcelable interface.
override val CREATOR = new Parcelable.Creator[User] {
override def createFromParcel( source: Parcel ) = new User( source )
override def newArray( size: Int ) = new Array[User]( size )
}
}
Alternatives
Scala comes with first class macro support (compile time reflection). This allows for code generation at compile time that may help to reduce boilerplate in use cases like this without sacrificing performance. To simplify Inter Process Communication (IPC) with the Parcelable contract, you could instead try one of the numerous JavaScript Object Notation libraries, or Scala Pickling, a project that aims to bring boilerplate-free serialization to Scala.
Further reading
- Parcelable vs. Serializable
A performance and usability comparison
- Scala Pickling
Scala serialization project
- Parcelable
Compile time code generation for Scala on Android