0

I have been looking for an solution on how to make my app not to loose data when orientation of phone changes. I have found one and it is adding this line of code

android:configChanges="orientation|keyboardHidden">

to android manifest. So i did it:

<?xml version="1.0" encoding="utf-8"?>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity"
        android:configChanges="orientation|keyboardHidden">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

And my data still get lost when orientation changes, could anyone please help me ? Thank you very much.

My java code:

public class MainActivity extends AppCompatActivity {
int scoreofShooter1 = 0;
int scoreofShooter2 = 0;

@Override

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public void addOneForShooter1(View view) {
    scoreofShooter1 = scoreofShooter1 + 1;
    displayForShooter1(scoreofShooter1);
}

public void addTwoForShooter1(View view) {
    scoreofShooter1 = scoreofShooter1 + 2;
    displayForShooter1(scoreofShooter1);
}
public void addThreeForShooter1(View view) {
    scoreofShooter1 = scoreofShooter1 + 3;
    displayForShooter1(scoreofShooter1);
}

public void addFourForShooter1(View view) {
    scoreofShooter1 = scoreofShooter1 + 4;
    displayForShooter1(scoreofShooter1);
}

public void addOneForShooter2(View view) {
    scoreofShooter2 = scoreofShooter2 + 1;
    displayForShooter2(scoreofShooter2);
}

public void addTwoForShooter2(View view) {
    scoreofShooter2 = scoreofShooter2 + 2;
    displayForShooter2(scoreofShooter2);
}
public void addThreeForShooter2(View view) {
    scoreofShooter2 = scoreofShooter2 + 3;
    displayForShooter2(scoreofShooter2);
}

public void addFourForShooter2(View view) {
    scoreofShooter2 = scoreofShooter2 + 4;
    displayForShooter2(scoreofShooter2);
}

public void resetScoreOfShooter1(View view) {
    scoreofShooter1 = 0;
    displayForShooter1(scoreofShooter1);
}

public void resetScoreOfShooter2(View view) {
    scoreofShooter2 = 0;
    displayForShooter2(scoreofShooter2);
}

public void displayForShooter1(int score) {
    TextView scoreView = (TextView) findViewById(R.id.shooter_1_score);
    scoreView.setText(String.valueOf(score));
}


public void displayForShooter2(int score) {
    TextView scoreView = (TextView) findViewById(R.id.shooter_2_score);
    scoreView.setText(String.valueOf(score));
}

}

Veranicus
  • 27
  • 5
  • 1
    Possible duplicate of [Save data and change orientation](http://stackoverflow.com/questions/12214600/save-data-and-change-orientation) – Asif Patel Mar 31 '17 at 21:18
  • Hi, sorry that it looks like an duplicate but I have read that topic and did not understood where is my mistake so I would be extremelly glad if someone were to help my specific case of this problem, thank you very much for understanding. – Veranicus Mar 31 '17 at 21:26

2 Answers2

1

Change this:

android:configChanges="orientation|keyboardHidden">

to:

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

"orientation": The screen orientation has changed — the user has rotated the device.

Note: If your application targets API level 13 or higher (as declared by the minSdkVersion and targetSdkVersionattributes), then you should also declare the "screenSize" configuration, because it also changes when a device switches between portrait and landscape orientations.

False
  • 101
  • 1
  • 10
0

Your solution is bad practice as stated in this great article

Perhaps the hackiest and most widely abused workaround is to disable the default destroy-and-recreate behavior by setting the android:configChanges attribute in your Android manifest. The apparent simplicity of this approach makes it extremely attractive to developers; Google engineers, however, discourage its use. The primary concern is that it requires you to handle device configuration changes manually in code. Handling configuration changes require you to take many additional steps to ensure that each and every string, layout, drawable, dimension, etc. remains in sync with the device’s current configuration, and if you aren’t careful, your application can easily have a whole series of resource-specific bugs as a result.

Another reason why Google discourages its use is because many developers incorrectly assume that setting android:configChanges="orientation" (for example) will magically protect their application from unpredictable scenarios in which the underlying Activity will be destroyed and recreated. This is not the case. Configuration changes can occur for a number of reasons—not just screen orientation changes. Inserting your device into a display dock, changing the default language, and modifying the device’s default font scaling factor are just three examples of events that can trigger a device configuration change, all of which signal the system to destroy and recreate all currently running Activities the next time they are resumed. As a result, setting the android:configChanges attribute is generally not good practice.

there are two scenarios: 1- if you just need to save some attributes just use onSavedInstanceState and onRestoreInstanceState

2- If you have a more complicated scenario where you have running Threads, AsyncTasks, Sockets. you could:

1- Manage the Object Inside a Retained Fragment as described here

2- the better solution is to use loaders which are created to solve this exact problem.

from android docs:

  • If you fetch the data directly in the activity or fragment, your users will suffer from lack of responsiveness due to performing potentially slow queries from the UI thread.

  • If you fetch the data from another thread, perhaps with AsyncTask, then you're responsible for managing both the thread and the UI thread through various activity or fragment lifecycle events, such as onDestroy() and configurations changes.

Loaders solve these problems and includes other benefits. For example:

Loaders run on separate threads to prevent janky or unresponsive UI. Loaders simplify thread management by providing callback methods when events occur. Loaders persist and cache results across configuration changes to prevent duplicate queries. Loaders can implement an observer to monitor for changes in the underlying data source. For example, CursorLoader automatically registers a ContentObserver to trigger a reload when data changes.

for your particular situation

use the following code:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        scoreofShooter1 = savedInstanceState.getInt("scoreofShooter1");
        scoreofShooter2 = savedInstanceState.getInt("scoreofShooter2");
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("scoreofShooter1", scoreofShooter1);
    outState.putInt("scoreofShooter2", scoreofShooter2);
}
humazed
  • 74,687
  • 32
  • 99
  • 138
  • link [2] is broken/not a valid link – Zharf Mar 31 '17 at 22:48
  • Hi, thank you very much for your help. The first posted solution which is a bad practise works also but my application is not complicated, I could do it through onSavedInstanceState and onRestoreInstanceState , the problem is that I don't know how to implement this and believe me that I have tried and read a tons of documentation but my oop skills are so low that even that is a problem for me, I am a complete beginner. I have posted my java code to my first post so if you would be so kind and look and it and just posted me a bit of exact code worked in that oncreate way I could work from there – Veranicus Apr 01 '17 at 07:15