Using Parcelable to Pass Highly Nested Classes Between Activities
Suppose I want to store a custom object of type MyObject
in Intent
. The way to do this is to make an MyObject
implementation Parcelable
. If one of the fields is MyObject
also a custom type object Widget
, then it's obvious what to do to Widget
implement Parcelable
too.
The problem is that Parcelable
there are a lot of templates to implement . You can work around this by not creating an Widget
implementation Parcelable
, but simply providing it with a constructor with Parcel
and a method writeToParcel
like this:
public final class Widget {
private final int a;
private final String b;
Widget(Parcel in) {
a = in.readInt();
b = in.readString();
}
void writeToParcel(Parcel out) {
out.writeInt(a);
out.writeString(b);
}
}
Then you can have a field Widget
in the object Parcelable
like this:
public class MyObject implements Parcelable {
private final int x;
private final Widget w;
MyObject(int x, Widget w) {
this.x = x;
this.w = w;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(x);
w.writeToParcel(out);
}
public static final Parcelable.Creator<MyObject> CREATOR
= new Parcelable.Creator<MyObject>() {
@Override
public MyObject createFromParcel(Parcel in) {
return new MyObject(in.readInt(), new Widget(in));
}
@Override
public MyObject[] newArray(int size) {
return new MyObject[size];
}
};
}
Is this an acceptable approach? Is it uniomatic android to have many custom classes in the project that can be written and read from Parcel
without actually embedding them Parcelable
? Or the fact that I am using Parcelable
to pass complex objects with many fields of custom types (which in turn have many fields of custom type, etc. etc.) indicate that I should not use Parcelable
in the first place ?
source to share
I would (and did) go with Parceler: https://github.com/johncarl81/parceler
Parceler is a code generation library that generates Android source code. You no longer need to do the Parcelable interface, writeToParcel () or createFromParcel (), or the public static final CREATOR. You just comment out the POJO with @Parcel and Parceler does the rest.
It is very easy to use.
source to share
Recommended Parcelable
when working with passing custom objects through intents in Android. No "easy" job. Since you are only dealing with one additional layer of custom object (widget), I would recommend that you do as well Widget
Parcelable
. You can also check this link to see why this is a better approach than using the default serialization. https://coderwall.com/p/vfbing/passing-objects-between-activities-in-android
source to share
If your classes are beans the best solution is the accepted one. If not, I found that you can (slightly) reduce the pain of implementation Parcelable
by creating abstract classes ParcelablePlus
and CreatorPlus
as follows.
ParcelablePlus
:
abstract class ParcelablePlus implements Parcelable {
@Override
public final int describeContents() {
return 0;
}
}
CreatorPlus
:
abstract class CreatorPlus<T extends Parcelable> implements Parcelable.Creator<T> {
private final Class<T> clazz;
CreatorPlus(Class<T> clazz) {
this.clazz = clazz;
}
@Override
@SuppressWarnings("unchecked")
public final T[] newArray(int size) {
// Safe as long as T is not a generic type.
return (T[]) Array.newInstance(clazz, size);
}
}
Then the class Widget
becomes:
public final class Widget extends ParcelablePlus {
private final int a;
private final String b;
Widget(int a, String b) {
this.a = a;
this.b = b;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(a);
out.writeString(b);
}
public static final Creator<Widget> CREATOR = new CreatorPlus<Widget>(Widget.class) {
@Override
public Widget createFromParcel(Parcel in) {
return new Widget(in.readInt(), in.readString());
}
};
}
source to share