Search code examples
javaandroidparcelableonrestoreinstancestateonsaveinstancestate

implementing Parcelable in a derived-graphic class for onSaveInstanceState(Bundle)


I want to save and restore some data for screen orientation changes (portrait/landscape).

For doing it, I implemented onSaveInstanceState and onRestoreInstanceState in my class that holds the list that I want to restore. It seems to be working, and in MyObject class I implemented Parcelable.

The problem is that my object extends GifImageButton and implement Parcelable so I get this error in my object constructors: "There is no default constructor available for pl.droidsonroids.gif.GifImageButton"

public class MyDerivedClass extends MyBaseClass { // extends AppCompatActivity
    ArrayList<MyObject> list;

        @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.episode_five);
    if(savedInstanceState == null || !savedInstanceState.containsKey("key"))     {
            String[] colors = {"black", "red"};
            String[] numbers = {"one", "two"};

            list = new ArrayList<MyObject>();
            for(int i = 0; i < numbers.length; i++)
                list.add(new MyObject(numbers[i], colors[i]));
        }
        else {
            list = savedInstanceState.getParcelableArrayList("key");
        }
    }

    @Override
     protected void onSaveInstanceState(Bundle outState) {
        outState.putParcelableArrayList("key", list);
        super.onSaveInstanceState(outState);
    }
    @Override
    protected void onRestoreInstanceState(Bundle inState) {
        list = inState.getParcelableArrayList("key");
        super.onSaveInstanceState(inState);
        init();
    }
    public void init() {
        list.add(new MyObject("three", "transparent"));
        list.add(new MyObject("for", "white"));
    }
}

and for the problem, view the code below:

I want to extends GifImageButton but then I get an error "There is no default constructor available for pl.droidsonroids.gif.GifImageButton" at:

public MyObject(String number, String color) AND public MyObject(Parcel in)

Note: if I remove: "extends GifImageButton" and "public MyObject(Context context, AttributeSet attrs)" then the code is compiled.

class MyObject extends GifImageButton implements Parcelable {
    String color;
    String number;

    public MyObject(Context context, AttributeSet attrs) {
        super(context, attrs);
        setImageResource(R.drawable.a);
    }

    public MyObject(String number, String color) {
        this.color = color;
        this.number = number;
    }

    private MyObject(Parcel in) {
        color = in.readString();
        number = in.readString();
    }

    public int describeContents() {
        return 0;
    }

    @Override
    public String toString() {
        return number + ": " + color;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(color);
        out.writeString(number);
    }

public static final Parcelable.Creator<MyObject> CREATOR = new     Parcelable.Creator<MyObject>() {
        public MyObject createFromParcel(Parcel in) {
            return new MyObject(in);
        }

        public MyObject[] newArray(int size) {
            return new MyObject[size];
        }
    };
}

Can I extend GifImageButton in my object class that implements Parcelable? if not then how can I fix it?


Solution

  • The error message appears because you need to call a constructor of the superclass in your constructor. If there is no explicit call, the compiler inserts a call to a constructor without arguments. However, all the super class constructors have some arguments, that's why the compilation fails.

    In your case I wouldn't implement Parcelable in your class at all. The superclass doesn't implement it, so you'd need to somehow save the state of the superclass also, which will not be possible to do. The superclass is a View, so it retains a reference to the current activity, which can't be put into a Parcel.

    What you should do instead is save not the instance itself, but the state you need. Your state is currently expressed by two strings. You can create a separate class State inside MyObject:

    static class State implements Parcelable {
        private String color;
        private String number;
    
        //Parcelable implementation omitted
    }
    

    Then you implement Parcelable for it. MyObject will have a field private State state instead of the current two fields, a constructor which takes a State, and a method State getState(), which will return the state. When you need to save the state, you don't save the object, you get its state and save it instead. When you need to restore, you restore the State first, then use it with the constructor to create a new MyObject with the same state as before.