I have an abstract class and its children, and I wanted to pass the children through one activity to another through intent.putExtra(String, Parcelable);
The activity receiving the Intent would accept any parcelable since it's an object extending the abstract class.
I made an implementation of Parcelable both in the abstract class and the children:
public abstract class MyAbstractClass implements Parcelable{
private double dField;
private Integer stringResource;
private MyEnum objEnumType;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
//TODO Age
parcel.writeDouble(dField); parcel.writeString(this.objEnumType.toString());
parcel.writeInt(stringResource);
}
public static final Parcelable.Creator<MyAbstractClass> CREATOR = new Creator<MyAbstractClass>() {
@Override
public MyAbstractClass createFromParcel(Parcel parcel) {
return null;
}
@Override
public MyAbstractClass[] newArray(int i) {
return new MyAbstractClass[0];
}
};
protected MyAbstractClass(Parcel in){
dField = in.readDouble();
this.objEnumType = MyEnum.valueOf(in.readString());
stringResource = in.readInt();
}
}
In the child class:
public class MyChildClass extends MyAbstractClass{
public int describeContents(){
return 0;
}
public void writeToParcel(Parcel out, int flags){
super.writeToParcel(out,flags);
}
public static final Parcelable.Creator<MyChildClass> CREATOR = new Creator<MyChildClass>() {
@Override
public MyChildClass createFromParcel(Parcel parcel) {
return null;
}
@Override
public MyChildClass[] newArray(int i) {
return new MyChildClass[0];
}
};
protected MyChildClass(Parcel in) {
super(in);
}
}
In the FirstActivity I was passing the parcelable, I wrote, but I get an error related to the constructor of the MyChildClass:
MyChildClass objChildClass = new MyChildClass(); //I got an error here, expecting a Parcel object?!
Intent intent = new Intent(this,SecondActivity.class);
intent.putExtra("extraParcelable",objChildClass);
startActivity(intent);
According to the Android Studio, MyChildClass expects a Parcel argument to MyChildClass, but how can I pass a Parcel if I want to send this class through an Intent?
EDIT
I added an empty constructor in both MyChildClass and MyAbstractClass:
MyChildClass(){super()}
And In the MyAbstractClass:
MyAbstractClass(){}
In the FirstActivity I added:
objChildClass.setDField = 2.5;
objChildClass.setObjEnumType = MyEnum.Type1;
objChildClass.setStringResource = getString(R.string.app_name);
Intent intent = new Intent(this,SecondActivity.class);
intent.putExtra("extraParcelable",objChildClass);
startActivity(intent);
In The SecondActivity:
class SecondActivity : AppCompatActivity() {
private val lbResult by lazy {findViewById<TextView>(R.id.lb_result)}
private val objReceived by lazy {intent?.extras?.getParcelable<MyAbstractClass>("extraParcelable")}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//
//...
//
lbResult.text = objReceived?.dField.toString() //I get a null here
}
}
By I get a null in lbResults. The code was working perfectly when I used intent.putExtras(String, Double), but now using parcelable is null if I use an empty constructor. Otherwise I get that error wanting to pass a Parcel as a constructor, (As I wrote above)
The problems I was facing with implementing Parcelable were due to simple mistakes I ignored about the constructors when dealing with Parcelables:
public MyChildClass(Parcel parcel){
super(parcel);
}
public MyChildClass(){super();}
I had also to match the constructor on the super class:
protected MyAbstractClass(Parcel in){
dField = in.readDouble();
this.objEnumType = MyEnum.valueOf(in.readString());
stringResource = in.readInt();
}
protected MyAbstractClass(){}
createFromParcel
method inside Parcelabe.Creator CREATOR
. This was my second mistake. Android studio autogenerated Parcelable.Creator
only puts return null
in this method. public static final Parcelable.Creator<MyChildClass> CREATOR = new Creator<MyChildClass>() {
@Override
public MyChildClass createFromParcel(Parcel parcel) {
return new MyChildClass(parcel); //It needs to replace the default `return null` by the instance of the class calling the constructor to pass the Parcel object
}
@Override
public MyChildClass[] newArray(int i) {
return new MyChildClass[0];
}
};
public T createFromParcel
from Parcelable.Creator CREATOR
requires an instance of the class, I removed Parcelable.Creator CREATOR
from MyAbstractClass, since being an abstract class I cannot create any instances thereNow I can pass my derived classes through the activities without null or complaining about the Parcel not passed throught the constructor