Question

I need to apply different layouts for portrait and landscape orientations of my activity. Besides, I need to show alert if orientation is portrait.

I have specified android:configChanges="orientation|keyboardHidden" in AndroidManifest. I also override onConfigurationChanged method like this:

@Override
public void onConfigurationChanged(Configuration newConfig)
{
    Log.d("tag", "config changed");
    super.onConfigurationChanged(newConfig);

    int orientation = newConfig.orientation;
    if (orientation == Configuration.ORIENTATION_PORTRAIT)
        Log.d("tag", "Portrait");
    else if (orientation == Configuration.ORIENTATION_LANDSCAPE)
        Log.d("tag", "Landscape");
    else
        Log.w("tag", "other: " + orientation);

    ....
}

While rotating from landscape to portrait log looks like:

config changed
Portrait

But while changing from portrait to landscape it looks like

config changed
Portrait
config changed
Landscape

Why onConfigurationChanged is called twice? How can I avoid it?

Was it helpful?

Solution

See my answer to another question here: https://stackoverflow.com/a/3252547/338479

In short, handling configuration changes correctly is hard to do. It's best to implement onRetainNonConfigurationInstance() which is called just before your application is about to be stopped and restarted due to a configuration change. Use this method to save anything you want ('this' is a good choice) and then let the system tear down your app.

When your app gets restarted with the new configuration, use getLastNonConfigurationInstance() to retrieve the state you just saved, and use it to continue your application without all that mucking about with bundles and shared preferences.

OTHER TIPS

You can simply save the previous orientation and check if it has really changed.

If you set in AndroidManifest.xml android:configChanges to keyboardHidden|orientation for your activity, onCreate etc... won't be called. That makes the implementation significantly easier to implement. But of course layout will change from portrait to landscape as well.

Is there any particular reason you chose to handle rotation in this manner? While it is quicker since the activity doesn't get restarted on an orientation change, it isn't typically recommended, if I recall correctly. Another way to handle orientation changes is instead of overriding onConfigurationChanged(), overriding onCreate(), onStart() or onResume() such that

@Override
public void onStart() {
    super.onStart();
    int orientation = getWindowManager().getDefaultDisplay().getOrientation();
    if(orientation == Configuration.ORIENTATION_PORTRAIT) {
        Log.i(TAG, "Orientation is portrait");
        // show whatever alerts here
    }
}

and then specifying two layouts - one for portrait, one for landscape. The portrait version of the layout would remain at res/layout/whatever.xml, and the landscape version would live in res/layout-land/whatever.xml. The AndroidGuys had written a bunch of good articles on this topic, see http://androidguys.com/?s=rotational+forces&x=9&y=9

I'm pretty sure you would want to use onCreate rather than onStart. The only difference appears to be that onStart will get called when the application comes to the foreground. That wouldn't be a case where you'd want to make the user wait for you to re-initialize the UI. Otherwise, just change your setContentView call based on that if condition.

Android starts a new instance of your activity when changing orientation so using onCreate is the ideal method. You will have to save/restore your activity's data obviously in order to pick up where you left off - but you should be doing this anyway since any number of events can unfocus/kill your application.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top