0

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);
    }
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
AndroWeed
  • 133
  • 2
  • 12
  • 1
    you should rather save the data(from the internet) only ... fx using either deprecated `Activity.getLastNonConfigurationInstance()` or with UI-less retainable fragment ... the all other stuff should be there ... GridView is saving the position of current item in `onSaveInstanceState` so you should be bother with this ... – Selvin Feb 05 '16 at 13:34
  • 1
    http://selvin.pl/MainActivity.java.txt check the CacheFragment class and it's usage ... the data obtained from internet is stored in `JSONArray CacheFragment.response` and it "survive" the screen orentation change ... loadData starts new request or immediately return data depends on if `response` is set already or not – Selvin Feb 05 '16 at 13:38
  • Thank you @Selvin for your help. I kinda tried Eugen's solution and it worked perfectly :) – AndroWeed Feb 05 '16 at 15:36
  • 2
    There is a small problem with savedInstanceState solution - the savedInstanceState limit (~1MB) ... so you should lookout on this solution ... also parcel/unparcel will take some CPU cycle ... when just retain an instance not - as you will get exactly the same data instance ... so, when I'm not saying that it is a bad solution I wouldn't use it by myself – Selvin Feb 05 '16 at 15:48
  • @Selvin : Thank you! This is what Google documentation says about large data and surviving Configuration Change : `...onSaveInstanceState() callback—it is not designed to carry large objects (such as bitmaps) and the data within it must be serialized then deserialized, which can consume a lot of memory and make the configuration change slow. ...`. [Here](http://developer.android.com/guide/topics/resources/runtime-changes.html). – AndroWeed Feb 10 '16 at 11:46
  • @Selvin : I examined the link you posted about the sample using Fragment to pass and restore data every configuration change, and it helped me change my approach by using it instead of Bundle. You made my day sir. Thank you again. – AndroWeed Feb 10 '16 at 18:58

1 Answers1

4

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());
}
Community
  • 1
  • 1
Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124
  • Dear friend Eugen Pechanec, I can't thank you enough for your kind and generous help..it worked like charm!! You saved not only my day, but also my life. Thank you so much!! And I'm so glad to know you :) – AndroWeed Feb 05 '16 at 15:31
  • 1
    @MouradJEMAÏL You just made my day :D Glad I could help. Now I recommend focusing on loading the items from internet effectively. You could look at this https://www.youtube.com/watch?v=BlkJzgjzL0c (although it might be a bit heavy duty). Since you have a new activity instance for every config change, you can't rely on simple async task which is tied to its original activity. Good luck! – Eugen Pechanec Feb 05 '16 at 16:55
  • Thank you my friend :) Really, the video sounds very interesting. I'm open to any resource that might optimize my practice in android development, and surely will help me learn more :) – AndroWeed Feb 05 '16 at 17:22