How to Avoid Restarting Activity When Orientation Changes on Android

How to prevent activity to restart after changing its orientation

It really is not recommended to prevent activity restart on config changes.

The recommended ways would either by saving and restoring UI state or by using ViewModel. Either one of them can solve your problem but it's better to use ViewModel approach.



Saving and restoring UI state

Saving state

Right before activity start, but right after config changes have been signaled, override Activity.onSaveInstanceState(Bundle) if you're saving activity state, or `Fragment.onSaveInstanceState(Bundle) if you're saving fragment state.

override fun onSaveInstanceState(outState: Bundle?) {
// Save your data into outState data bundle. And then make sure to
// call the super method.
super.onSaveInstanceState(outState)
}

Restoring state

After activity restart due to config changes, restore the previously saved data
and apply it to the UI.

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ... inflate layout, etc...
if (savedInstanceState != null) {
// If savedInstanceState is not null, that means this activity is restoring from
// config changes. All your saved data in onSaveInstanceState() should be accessible
// from savedInstanceState bundle.
// ... restore values from savedInstanceState and apply to your views ...
} else {
// Initialize vie
}
}


Using ViewModel

This approach is relatively new introduced by Google as part of Android Jetpack library.
Instead of overriding onSaveInstanceState(Bundle) and checking savedInstanceStatefor null, your data is persisted inside aViewModel` and will survive from configuration changes.

Basic

Initialize your data inside the ViewModel and access them from your activity or fragment.

class MyViewModel : ViewModel() {
var myList: List<User> = emptyList()
var currentTabIndex: Int = 0

init {
// Initialize your data here...
}
}
class MyFragment : Fragment() {
private val model by viewModels<MyViewModel>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ... inflate layout, etc...
viewPager.setCurrentItem(model.currentTabIndex, false)
// Fetch the values from `ViewModel` and apply to your fragment.
}
}

More about ViewModel

For better usage of ViewModel, it's better to learn from the official comprehensive guide.

prevent activity restarting when orientation changes

Write this code in your activity

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

if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
setContentView(R.layout.landscapeView);

} else {
setContentView(R.layout.portraitView);
}
}

And also add this line in your Manifest file

android:configChanges="orientation|keyboardHidden|screenSize"

So this will handle both things, it will not restart your activity and will load the layout as per your orientation changes.

Android App orientation change restarts activity

Actually you shouldn't prevent the Activity to be restarted. It is neccessary to recreate the Activity after a rotation change for several reasons. One of it is that the layout has to be inflated to deal with the changed screen size and things like that (it's easy to imagine that the layout is totally different in portrait than it is in landscape mode).
However, there is a way you can tell the system that you deal with the screen changes by yourself. Therefore change the line in your manifest

android:configChanges="orientation|keyboardHidden"

to

android:configChanges="orientation|screenSize"

The activity won't be recreated then. You'll get a callback via the onConfigurationChanged() method so you can do something when the orientation has changed. If you don't want to do anything when the configuration has changed, just don't override the onConfigurationMethod() in your Activity. Read this section in the Android Developers API Guide for more information.

I got this from this answer. There are two more approaches in the answer but I think the one I described above is the best in your case.

EDIT: Maybe you have to add keyboard|keyboardHidden to the android:configChanges attribute as well, as stated in this answer


EDIT #2: If you want to retrieve the current orientation of the device you can call

Activity.getResources().getConfiguration().orientation

which will return the constants ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE.

If you're interested in the exact rotation angle, use

int rotation =  getWindowManager().getDefaultDisplay().getRotation();

and implement a differentiation with something like a switch case described here.

And a third way to determine the device's rotation is getRequestedOrientation() which will return a constant defined in the documentation

android prevent refresh on change orientation

By declaring android:configChanges="orientation|screenSize" you instruct Activity Manager to not restart your activity and let you handle configuration change via onConfigurationChanged().

If your application doesn't need to update resources during a specific configuration change and you have a performance limitation that requires you to avoid the activity restart, then you can declare that your activity handles the configuration change itself, which prevents the system from restarting your activity.

Source: http://developer.android.com/guide/topics/resources/runtime-changes.html

Which means that onCreate() will be skipped on configuration changed, and you cannot swap your layout (since onCreate() is where you recreate the view).

In your case, you want to change layout, so there is no choice but to refresh your activity, which means to remove android:configChanges="orientation|screenSize". If you want to keep the state, you can save and check the Bundle passed to your onCreate() to restore state accordingly.

@Override
protected void onCreate(Bundle savedInstanceState) {
...
// set your layoutId according to landscape/portrait
setContentView(layoutId);
if (savedInstanceState != null) {
// restore your state here
}
...
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// save your state here
}

For more reference: http://developer.android.com/training/basics/activity-lifecycle/recreating.html

Android: manual screen orientation without restarting the activity?

For manaul orientation change:

<activity
android:name=".VideoDetails"
android:configChanges="orientation"/>

public class VideoDetails extends Activity {
...
onStart() {
setRequestedOrientation(orientation);
}
onConfigurationChanged(Configuration newConfig){
// do stuff for orientation change.
}
onClick() {
setRequestedOrientation(orientation);
}
}

For auto-orientation detect:

<activity
android:name=".VideoDetails"
android:configChanges="orientation"/>

public class VideoDetails extends Activity {
...
onConfigurationChanged(Configuration newConfig){
// do stuff for orientation change.
}
}

Don't reload application when orientation changes

There are generally three ways to do this:

  1. As some of the answers suggested, you could distinguish the cases of your activity being created for the first time and being restored from savedInstanceState. This is done by overriding onSaveInstanceState and checking the parameter of onCreate.

  2. You could lock the activity in one orientation by adding android:screenOrientation="portrait" (or "landscape") to <activity> in your manifest.

  3. You could tell the system that you meant to handle screen changes for yourself by specifying android:configChanges="orientation|screenSize" in the <activity> tag. This way the activity will not be recreated, but will receive a callback instead (which you can ignore as it's not useful for you).

Personally I'd go with (3). Of course if locking the app to one of the orientations is fine with you, you can also go with (2).



Related Topics



Leave a reply



Submit