Handle screen rotation without losing data - Android

AndroidAndroid LayoutAndroid Intent

Android Problem Overview


I'm becoming crazy figuring out what is the best way to handle screen rotation. I read hundreds of questions/answers here but I'm really confused.

How can I save myClass data before the activity is re-created so I can keep everything for redrawing activity without another useless initialization?

Is there a cleaner and better way than parcelable?

I need to handle rotation because I want to change layout in Landscape mode.

public class MtgoLifecounterActivity extends Activity {
	
	MyClass myClass;

	// Called when the activity is first created
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 		
		If ( ?? first run...myClass == null ? ) {
			myClass = new MyClass();
		} else {
			// do other stuff but I need myClass istance with all values.
		}
		// I want that this is called only first time. 
		// then in case of rotation of screen, i want to restore the other instance of myClass which
		// is full of data.
    }

Android Solutions


Solution 1 - Android

In Activity Tag of Manifest you should have to mention

<activity
        android:name="com.example.ListActivity"
        android:label="@string/app_name" 
        android:configChanges="keyboardHidden|orientation">

If you are using Android 2.3(API level 13 ) and above use

<activity
        android:name="com.example.Activity"
        android:label="@string/app_name" 
        android:configChanges="keyboardHidden|orientation|screenSize">

It should have to work.

It will work only with activity tag and not with application tag

Solution 2 - Android

can use override method onSaveInstanceState() and onRestoreInstanceState(). or to stop calling onCreate() on screen rotation just add this line in your manifest xml android:configChanges="keyboardHidden|orientation"

note: your custom class must implements Parcelable example below.

@Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("obj", myClass);
    }

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onRestoreInstanceState(savedInstanceState);
 myClass=savedInstanceState.getParcelable("obj"));
}

public class MyParcelable implements Parcelable {
     private int mData;

 public int describeContents() {
     return 0;
 }

 /** save object in parcel */
 public void writeToParcel(Parcel out, int flags) {
     out.writeInt(mData);
 }

 public static final Parcelable.Creator<MyParcelable> CREATOR
         = new Parcelable.Creator<MyParcelable>() {
     public MyParcelable createFromParcel(Parcel in) {
         return new MyParcelable(in);
     }

     public MyParcelable[] newArray(int size) {
         return new MyParcelable[size];
     }
 };

 /** recreate object from parcel */
 private MyParcelable(Parcel in) {
     mData = in.readInt();
 }


}

Solution 3 - Android

May be this is solved already but just for a small update for new members who stuck on it, just have a look at Google Developer Site, From API level 13, you just need to add this code to Manifest:

<activity android:name=".SplashScreensActivity"
          android:configChanges="orientation|keyboardHidden|screenSize"
          android:label="@string/app_name">

when one of these configurations change, SplashScreensActivity does not restart. Instead, the SplashScreensActivity receives a call to onConfigurationChanged(). This method is passed a Configuration object that specifies the new device configuration. By reading fields in the Configuration, you can determine the new configuration and make appropriate changes by updating the resources used in your interface. At the time this method is called, your activity's Resources object is updated to return resources based on the new configuration, so you can easily reset elements of your UI without the system restarting your activity.

Solution 4 - Android

The problem here is that you are losing the "state" of the App. In OOPs, What is a State? The Variables! Exactly! Hence when you are losing the data of your variables.

Now here is what you can do, Find Out the variables which are losing their states.

enter image description here

When you rotate your device, your present activity gets completely destroyed, ie goes through onSaveInstanceState() onPause() onStop() onDestroy() and a new activity is created completely which goes through onCreate() onStart() onRestoreInstanceState.

The Two Methods in the bold, onSaveInstanceState() saves the instance of the present activity which is going to be destroyed. onRestoreInstanceState This method restores the saved state of the previous activity. This way you don't lose your previous state of the app.

Here is how you use these methods.

 @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);

        outState.putString("theWord", theWord); // Saving the Variable theWord
        outState.putStringArrayList("fiveDefns", fiveDefns); // Saving the ArrayList fiveDefns
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onRestoreInstanceState(savedInstanceState, persistentState);

        theWord = savedInstanceState.getString("theWord"); // Restoring theWord
        fiveDefns = savedInstanceState.getStringArrayList("fiveDefns"); //Restoring fiveDefns
    }

EDIT : A Better Approach: The above approach toward maintaining your data isn't the best way to maintain data in production code/apps. Google IO 2017 introduced ViewModel to protect your data against configurational changes (like Screen Rotation). Keeping all data inside the activity using variables isn't a good software design and violates the Single Responsibility Principle hence separate your data storage using ViewModel from the activities.

  • ViewModel will be responsible for the data to be displayed.
  • Activity will be responsible for how to display the data.
  • Use additional repository class if you have an increasing complexity of storing the data.

That's just one of the way to separate classes and their responsibility, which will go a long way while making well-architectured apps.

Solution 5 - Android

If you do not have a need for your activity to be restarted just set the configChanges attribute on your activity in the AndroidManifest.xml to this:

    android:configChanges="keyboard|keyboardHidden|orientation"

This will tell the OS that you are going to take care of handling a rotation and will not restart your activity. Using this method will remove the need for you to have to save any kind of state.

Solution 6 - Android

There are two (good) ways about this. Make your class implement Parcelable and put it in a bundle in onSaveInstanceState(), or, if it's more complex (e.g. an AsyncTask), return it in onRetainNonConfigurationInstance().

Then there's also the lazy way where you just stop reacting to configuration changes.

Solution 7 - Android

Its solve my problem.

<activity android:name=".MyActivity"
      android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
      android:label="@string/app_name">

Solution 8 - Android

from the documentation:

> Note: If your application targets Android 3.2 (API level 13) or > higher, then you should also declare the "screenSize" and > "screenLayout" configurations, because they might also change when a > device switches between portrait and landscape orientations.

so what you shpuld write will be :

<android:configChanges="keyboardHidden|orientation|screenSize|screenLayout">

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRiccardo NeriView Question on Stackoverflow
Solution 1 - AndroidBhagwat KView Answer on Stackoverflow
Solution 2 - AndroidMohammed Azharuddin ShaikhView Answer on Stackoverflow
Solution 3 - AndroidZak ChapmanView Answer on Stackoverflow
Solution 4 - AndroiddevDeejayView Answer on Stackoverflow
Solution 5 - AndroidBobbake4View Answer on Stackoverflow
Solution 6 - AndroiddmonView Answer on Stackoverflow
Solution 7 - AndroidDalvinder SinghView Answer on Stackoverflow
Solution 8 - AndroidMohammed FathiView Answer on Stackoverflow