Question

i want to do_something() whenever the device rotates from Portrait to Landscape.

i have added <activity android:configChanges="orientation" > in my manifest. So onConfigurationChanged() will be called whenever i rotate my device. And it will not re-create the Activity.

In my onConfigurationChanged() function:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        do_something();
    }
    then_fire_off_the_screen_rotation_as_normal();
    // which means re-start the Activity
    // i expect it will fire off onSaveInstanceState() -> onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()
}

My problem is, i dont know what can i do in then_fire_off_the_screen_rotation_as_normal().

i have tried using setRequestedOrientation() but it seems it is not the function serving this purpose:

When i pass in ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, ActivityInfo.SCREEN_ORIENTATION_SENSOR, or ActivityInfo.SCREEN_ORIENTATION_USER, the Activity is still not re-started. (Just like not calling.)

When i pass in ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, the orientation sensor turned off. (As it said.)

When i pass in ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, the Activity was Force Close with AndroidRuntime:NullPointerException.


(Be specific: It is because there are programmatically added Fragments in the Portrait layout, but not in the Landscape layout. In the do_something() function, i will remove those Fragments, as they are not needed in Landscape mode.)

Was it helpful?

Solution

Well, i guess this simple way can serve what i want to:

Not to add <activity android:configChanges="orientation" >. Means NO NEED OVERRIDE onConfigurationChanged().

In onSaveInstanceState():

@Override
protected void onSaveInstanceState(Bundle outState) {
    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        do_something();
    }
    super.onSaveInstanceState(outState);
}

* Be sure you do_something() before super.onSaveInstanceState().

(Because in my case, i remove the Fragments from the Layout, and from the Activity. If it is after super.onSaveInstanceState(), the Layout will already be saved into the Bundle. Then the Fragments will also be re-created after the Activity re-creates. ###)

### I have proved this phenomenon. But the reason of What to determine a Fragment restore upon Activity re-create? is just by my guess. If you have any ideas about it, please answer my another question. Thanks!


Well, further improvement on the method above, which fixes the problem raised in the first comment: (still simple)

@Override
protected void onSaveInstanceState(Bundle outState) {
    if (isPortrait2Landscape()) {
        do_something();
    }
    super.onSaveInstanceState(outState);
}

private boolean isPortrait2Landscape() {
    return isDevicePortrait() && (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}

and the isDevicePortrait() would be like:

private boolean isDevicePortrait() {
    return (findViewById(R.id.A_View_Only_In_Portrait) != null);
}

* Notice that we cannot use getResources().getConfiguration().orientation to determine if the device is currently literally Portrait. It is because the Resources object is changed RIGHT AFTER the screen rotates - EVEN BEFORE onSaveInstanceState() is called!!

If you do not want to use findViewById() to test orientation (for any reasons, and it's not so neat afterall), keep a global variable private int current_orientation; and initialise it by current_orientation = getResources().getConfiguration().orientation; in onCreate(). This seems neater. But we should be aware not to change it anywhere during the Activity lifecycle.

OTHER TIPS

 // which means re-start the Activity
 // i expect it will fire off onSaveInstanceState() -> onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()

This assumption that onPause(), onStop(), etc. will fire is not correct. By using onConfigurationChanged you are telling Android to not go through those steps and instead you will handle the saving of information on the layout in temp variables and then recall the InitializeUI() and then set the layout back to how you want. I will post an example of something I have that is similar and working for me in one moment.

Edit: Here is the sample

@Override
public void onConfigurationChanged(Configuration newConfig){
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);
    Log.i("configChange", "configChange");

    String tmp = connect.getText().toString();
    boolean onTmp = on.isEnabled();
    boolean offTmp = off.isEnabled();
    boolean connTmp = reconnect.isEnabled();

    InitializeUI();

    connect.setText(tmp);
    on.setEnabled(onTmp);
    off.setEnabled(offTmp);
    reconnect.setEnabled(connTmp);
}

now my InitializeUI() method is nothing but a bunch of findViewById's and seetting up the onClickListeners. Also make sure to call InitializeUI() in youronCreate()`.

Hope this helps some.

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