0

I have the following 2 values folders under my project resources :

  1. This is my dimens.xml for portrait display of a 320dp width screen :

enter image description here

  1. This is my dimens.xml for landscape display of a 320dp width screen :

enter image description here

What I'm getting is a correct display at the application start (for the landscape display as well as the portrait display) :

  • Application starts in portrait mode correctly :

enter image description here

  • Application starts in landscape mode correctly :

enter image description here

Now my problem is when I rotate the screen during application runtime (say that the application first started in portrait mode), the application doesn't seem to retrieve values from the correct values folders which is supposed to be "values-w320dp-land" :

enter image description here

And vice-versa, if I rotate the screen after I started the application in ladscape mode, the application doesn't seem to retrieve values from the correct values folders which is supposed to be "values-w320dp-port", and I get this :

enter image description here

UPDATE 1

This is the activity declaration in AndroidManifest.xml :

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name=".utils.json.VolleyApplication" >

        <activity
            android:name="com.test.momo.CategoriesActivity"
            android:label="@string/app_name"
            android:configChanges="orientation|screenSize" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <!--Monitor for Changes in Connectivity-->
                <!--<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>-->
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

</application>

And this is my GridView declaration in the activity layout :

<GridView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/gridview_categories"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:columnWidth="@dimen/gridview_row_item_size"
            android:numColumns="@integer/num_columns"
            android:verticalSpacing="@dimen/gridview_row_item_spacing"
            android:horizontalSpacing="@dimen/gridview_row_item_spacing"
            android:stretchMode="none"
            android:layout_marginLeft="@dimen/gridview_row_item_spacing"
            android:layout_marginRight="@dimen/gridview_row_item_spacing"
            android:scrollbars="none"/>

UPDATE 2

So I finally got very close to the solution. Now when I rotate my screen at runtime, my GridView adjusts itself to the portrait ot landscape mode correctly after I did some changes on the code of the activity here :

@Override
public void onResume() {
    super.onResume();

    gridView.setNumColumns(getResources().getInteger(R.integer.num_columns));
    gridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.gridview_row_item_size));
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    gridView.setNumColumns(getResources().getInteger(R.integer.num_columns));
    gridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.gridview_row_item_size));
}

Except that, this is what I get when (and only when) I rotate screen from portrait to landscape at runtime :

enter image description here

As you can see, the first element of my GridView seems to preserve its height and width values of portrait mode. While the rest of the GridView elements display correctly.

What am I missing here?

AndroWeed
  • 133
  • 2
  • 12
  • Your activity has `android:configChanges="orientation"` in `AndroidManifest.xml`. http://stackoverflow.com/questions/7818717/why-not-use-always-androidconfigchanges-keyboardhiddenorientation How to fix it? Remove the line and start handling your async jobs properly. Good luck! – Eugen Pechanec Feb 03 '16 at 02:14
  • @EugenPechanec : Thank you for your answer, but removing `android:configChanges="orientation"` from manifest causes the activity to recreate at every screen rotation, which I need to prevent even if that shows a correct display after every screen rotation. How can I make my application show a correct display on screen rotation at runtime, and at the same time, preventing activity to recreate at every screen rotation event? – AndroWeed Feb 03 '16 at 08:41
  • Please have a look at UPDATE 2 in my post. – AndroWeed Feb 03 '16 at 13:23

1 Answers1

1

When you specify android:configChanges in your manifest, the activity will receive a onConfigurationChanged callback. An implementation could look as follows:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    // Absolutely detach any adapters from lists.
    // RecyclerView adapters have caches that need to be cleared.
    // We can reuse adapter but not widgets.
    mList.setAdapter(null);

    // Inflate new view hierarchy.
    setContentView(R.layout.the_same_layout_as_in_on_create);

    // Update variables so they point to newly inflated widgets
    ButterKnife.bind(this); // update variables to point 

    // Reattach adapters
    mList.setAdapter(mAdapter);

    // Here follows everything else that touches widgets in onCreate...
}

Please note that if I changed language on my phone the activity would still do a full restart since it's not in android:configChanges.

Also note that when using this approach the activity does not follow the lifecycle onPause-onStop-onDestroy-onCreate-onStart-onResume.

My advice is learn how to properly save state and fragments and just recreate the whole activity. The most expensive operation is inflating layout and you have to do that anyway.

Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124
  • Please have a look at UPDATE 2 in my post. – AndroWeed Feb 03 '16 at 13:23
  • @MouradJEMAÏL Re UPDATE 2: Did you also notice that when you start the activity in landscape and rotate to portrait the toolbar still has only 48dp height and small font size? And vice versa. Stop trying to invent some grand scheme how to screw over the framework in the name of marginal or none at all speed boost. Just recreate the activity. May I ask what's preventing you from recreating the activity? That could be a good SO question. – Eugen Pechanec Feb 03 '16 at 13:32
  • Also why set column numbers in onResume? That's onCreate material (where you setup the layout). – Eugen Pechanec Feb 03 '16 at 13:35
  • Recreating the activity means reloading the GridView and repeating all the process to retrieve all data from internet. So that's why it doesn't suit me. Please look at Google Play Store application when you click on Plus button, you get a nice GridView that even when you rotate screen, it adjusts to screen orientation without it being refreshed again. Which is exactly my purpose. – AndroWeed Feb 03 '16 at 13:45
  • Also, at runtime, when switching from landscape to portrait, GridView elements are displayed correctly. So the problem only occurs when switching from portrait to landscape. – AndroWeed Feb 03 '16 at 13:51
  • 1
    Well then read my answer. You have to recreate the layout, no way around that. But you don't have to reload the data. The adapter stays the same, still loaded with data or your async task is still running and can access non-null adapter instance. – Eugen Pechanec Feb 03 '16 at 13:57
  • Thank you for your help. But, what you're suggesting means the destruction of the GridView (even if the adapter is preserved) along with the activity, on screen rotation. This is not how the GridView of Google Play Store application works. So it's got to be another way to adapt the GridView rows size to screen width, on screen rotation, without any necessity to go through activity destruction or any need for saved instance. See what I mean? – AndroWeed Feb 04 '16 at 09:44
  • Alright, I just decompiled Play Store's AndroidManifest.xml. Here's the MainActivity entry: `` I don't see any configChanges... The layout reloads very quickly and it just plugs in data that's already loaded. Convinced yet? It's 2016, don't worry about recreating activity ;) – Eugen Pechanec Feb 04 '16 at 10:08
  • Easy Eugen :) You know? This is my 1st android application. So I'm kinda still learning stuff about android. Thank you again for your generous assistance. So how do you think they've made it that way then? Coz, the fact that you scroll down in Google Play GridView and then rotate screen (to landscape) and figure out you're pointed at the same row you reached in portrait mode, made me have a strong feeling that the activity was never destroyed, on screen rotation. If not, then in your opinion how's it possible to achieve such a behaviour? Thank you. – AndroWeed Feb 04 '16 at 10:30
  • It's alright, I've been at it for 3 years, just trying to save you the headache :) Views can save information across config changes such as orientation change. GridView will remember scroll position automatically as long as you attach the adapter in `onCreate` (you can't scroll gridview without items, it would reset to zero). Play store uses some custom sugar, it scrolls to section header on orientation change, but that's not important now. It feels seamless and yet the activity recreates. – Eugen Pechanec Feb 04 '16 at 10:42
  • @MouradJEMAÏL See the link in my first comment. It explains how view state is saved. Basically as long as the view has unique ID in that layout its state will be saved. – Eugen Pechanec Feb 04 '16 at 10:56
  • Thank you very much. I'll examine the link you posted and make a research about the approach you suggested on me to get more familiar with the save state possibility (which is new for me) :) – AndroWeed Feb 04 '16 at 11:05
  • I'll keep you informed about it ;) – AndroWeed Feb 04 '16 at 11:06
  • Hi mate, I just created a new thread [http://stackoverflow.com/questions/35224921/restore-android-gridview-after-screen-orientation-change-without-reloading-it](here) (more precise one). I made reasearch about `onSaveInstanceState()` as you suggested but I really getting confused on how to apply that in GridView's case. No clear answers yet. Please can you help me more? – AndroWeed Feb 05 '16 at 13:39
  • Thank you. Your advice helped me learn new good stuff about dealing with Android app configuration change. – AndroWeed Feb 10 '16 at 19:41