Search code examples
androidgridviewscreen-orientationrestoreandroid-configchanges

Restore Android GridView after screen orientation change (without reloading it)


I'm new to Android (this is my first application) and I made a GridView in an Activity which I'd like it to be responsive according to screen position (portrait / landscape). Of course I made some custom layout values of GridView rows width for portrait as well as for landscape, and it works perfectly.

Except that, on every screen orientation change, the GridView is reloading again. And that's not good for user experience. I only like the GridView (and definitely its rows) to adjust to new screen width without doing all the onCreate() instructions (retrieving GridView's data from internet, assigning retrieved data in a HashMap object, setting the GridView's Adapter, then display the GridView's rows).

I went through many forum threads and some Google documentation that talk about restoring simple values, but never found an answer for restoring a GridView without having it to reload again.

I read about onSaveInstanceState() and onRestoreInstanceState(), but I didn't know how to use them in my case (GridView case).

Could any one provide a simple code sample for this? Or at least some headlines to follow?

Here's some of what I tried in my code, in the Activity class :

    private Parcelable mListInstanceState;
    private Parcelable mAdapterInstanceState;

    private GridView gridView = null;
    private MyAdapter myAdapter = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       gridView = (GridView) findViewById(R.id.gridview);

       // Check whether we're recreating a previously destroyed instance
       if(savedInstanceState != null) {
            // Restore value of members from saved state
            mListInstanceState = savedInstanceState.getParcelable("gridview");
            mAdapterInstanceState = savedInstanceState.getParcelable("adapter");
       }
       else {
            // Retrieve data from internet, fill HashMap object, 
            // set Adapter and display GridView only for the first time the activity is created
            attemptToDisplayGirdViewItems();
       }
    }

    @Override
    protected void onSaveInstanceState(Bundle state) {
        // Save activity state

        super.onSaveInstanceState(state);

        state.putParcelable("gridview", gridView.onSaveInstanceState());
        // state.putParcelable("adapter", myAdapter);               
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        // Retrieve and restore activity state

        // Restore state members from saved instance
        mListInstanceState = savedInstanceState.getParcelable("gridview");
        mAdapterInstanceState = savedInstanceState.getParcelable("adapter");

        super.onRestoreInstanceState(savedInstanceState);
    }

Solution

  • You don't need to save the views. If they have ID, they'll be saved automatically (such as scroll position of a GridView). What you need to save is the adapter's data set.

    Your adapter presumably holds a list of items. Unless these items are primitives or String or implement Serializable, they need to implement Parcelable for this to work.

    See here how to do that: How can I make my custom objects Parcelable?

    Your adapter needs a getItems method which returns the data set - an ArrayList of your parcelable items. It also needs to have a setItems(...) method or a constructor taking a list of items as parameter.

    Then your activity will look like this:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.activity_main);
        gridView = (GridView) findViewById(R.id.gridview);
    
        myAdapter = new MyAdapter(); // Create empty adapter.
        if(savedInstanceState != null) {
            ArrayList<MyItem> items = savedInstanceState.getParcelableArrayList("myAdapter");
            myAdapter.setItems(items); // Load saved data if any.
        }
        gridView.setAdapter(myAdapter);
    }
    
    @Override
    protected void onSaveInstanceState(Bundle state) {
        super.onSaveInstanceState(state);
        state.putParcelableArrayList("myAdapter", myAdapter.getItems());
    }