onsaveinstancestate only works once? - android

I have an app with two layouts (portrait and landscape). There are 4 int values I want to save so they don't get erased on rotation. For that, I call on save instance and then I recover the state on the onCreate method like this:
private int operando1;
private int operando2;
private int operador;
private int contadorIntentos;
private String operadorTxt;
private static final String CONTADOR_INTENTOS = "contadorIntentos";
private static final String OPERANDO1 = "operando1";
private static final String OPERANDO2 = "operando2";
private static final String OPERADOR = "contadorIntentos";
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(CONTADOR_INTENTOS, contadorIntentos);
outState.putInt(OPERANDO1, operando1);
outState.putInt(OPERANDO2, operando2);
outState.putInt(OPERADOR, operador);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_actividad_principal);
//other random code
Random generador = new java.util.Random();
if (savedInstanceState != null){
contadorIntentos = savedInstanceState.getInt(CONTADOR_INTENTOS);
operando1 = savedInstanceState.getInt(OPERANDO1);
operando2 = savedInstanceState.getInt(OPERANDO2);
operador = savedInstanceState.getInt(OPERADOR);
}else {
contadorIntentos = 0;
operando1 = generador.nextInt(1000);
operando2 = generador.nextInt(1000);
operador = generador.nextInt(4);
}
Well, it turns out that it only saves the state once. after the first rotation (when it saves correctly) if I modify things and rotate again it recovers the state of the first rotation. It's like onsaveinstancestate only works once. Why?

Because savedInstanceState isn't null in all of the subsequent rotations, you are never generating new numbers (ex: never calling this again: operando1 = generador.nextInt(1000)...etc...)

Related

Save state of StreetViewFragment when orientation changes

I am trying to save the current position of the StreetViewPanorama in the StreetViewFragment so for example if the user is originally in Portrait and changes the location in the StreetViewPanorama by tapping on the arrows and explore the area and then switches to Landscape I want to set the last location to be restored so the user can continue exploring the area. Currently, the streetViewPanorama is Null when I try to access "streetViewPanorama.getLocation()" but this is not the problem. I think that my way of saving the state is not right and there should be a better way. So I am asking for your suggestions, please!
This is my StreetViewFragment's code:
public class StreetViewFragment extends ViperFragment implements OnStreetViewPanoramaReadyCallback,
PropertyDetailsStreetView {
private static final String KEY_PROPERTY_ID = "property_id_street_view";
private static final String KEY_PROPERTY_LAT = "property_lat";
private static final String KEY_PROPERTY_LON = "property_lon";
private Bundle savedInstances;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
streetViewPanoramaFragment = (StreetViewPanoramaFragment)
getActivity().getFragmentManager().findFragmentById(R.id.streetviewpanorama);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(this);
savedInstances = savedInstanceState;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putDouble(KEY_PROPERTY_LAT, streetViewPanorama.getLocation().position.latitude);
outState.putDouble(KEY_PROPERTY_LON, streetViewPanorama.getLocation().position.longitude);
super.onSaveInstanceState(outState);
}
#Override
public void onStreetViewPanoramaReady(StreetViewPanorama streetViewPanorama) {
this.streetViewPanorama = streetViewPanorama;
presenter.onStreetViewPanoramaReady(getArguments().getLong(KEY_PROPERTY_ID));
if (savedInstances != null) {
this.streetViewPanorama.setPosition(
new LatLng(savedInstances.getLong(KEY_PROPERTY_LAT),
savedInstances.getLong(KEY_PROPERTY_LON)));
}
}
After giving this a bit more tinkering I came with the following solution wich saves the state of the current position of the street view fragment and restores it. Works good.
public class StreetViewFragment extends ViperFragment implements OnStreetViewPanoramaReadyCallback,
PropertyDetailsStreetView {
private static final String KEY_PROPERTY_ID = "property_id_street_view";
private static final String KEY_PROPERTY_LAT = "property_lat";
private static final String KEY_PROPERTY_LON = "property_lon";
private StreetViewPanoramaFragment streetViewPanoramaFragment;
private StreetViewPanorama streetViewPanorama;
private Bundle localBundle;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
streetViewPanoramaFragment = (StreetViewPanoramaFragment)
getActivity().getFragmentManager().findFragmentById(R.id.streetviewpanorama);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(this);
this.localBundle = savedInstanceState;
}
#Override
public void onSaveInstanceState(Bundle outState) {
if (streetViewPanoramaFragment != null) {
outState.putDouble(KEY_PROPERTY_LAT,
streetViewPanorama.getLocation().position.latitude);
outState.putDouble(KEY_PROPERTY_LON,
streetViewPanorama.getLocation().position.longitude);
}
super.onSaveInstanceState(outState);
}
#Override
public void onStreetViewPanoramaReady(StreetViewPanorama streetViewPanorama) {
this.streetViewPanorama = streetViewPanorama;
presenter.onStreetViewPanoramaReady(getArguments().getLong(KEY_PROPERTY_ID));
if (localBundle != null) {
this.streetViewPanorama.setPosition(
new LatLng(localBundle.getDouble(KEY_PROPERTY_LAT),
localBundle.getDouble(KEY_PROPERTY_LON)));
}
}
If it extends Fragment class, then what about using setRetainInstance method? It allows you to save necessary variable(s) not destoying your fragment when device rotates. You can read about usage of this method from my article:
Simple trick to use and manage Toolbar with Fragments in Android

Data saving when orientation changes

I have put a condition in onCreate() method to check if there exist some previous data or not. But it is not working.
please guide me.
And I don't want to use onRestoreSavedState() method for this.d
public class ActivityOne extends Activity {
Use these as keys when you're saving state between reconfigurations
private static final String RESTART_KEY = "restart";
private static final String RESUME_KEY = "resume";
private static final String START_KEY = "start";
private static final String CREATE_KEY = "create";
String for LogCat documentation
private final static String TAG = "Lab-ActivityOne";
private int mCreate=0, mRestart=0, mStart=0, mResume=0;
You will need to increment these variables' values when their
corresponding lifecycle methods get called.
TODO: Create variables for each of the TextViews
private TextView mTvCreate, mTvRestart, mTvStart, mTvResume;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
TODO: Assign the appropriate TextViews to the TextView variables
mTvCreate=(TextView)findViewById(R.id.create);
mTvRestart=(TextView)findViewById(R.id.restart);
mTvResume=(TextView)findViewById(R.id.resume);
mTvStart=(TextView)findViewById(R.id.start);
Button launchActivityTwoButton = (Button) findViewById(R.id.bLaunchActivityTwo);
launchActivityTwoButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=null;
intent = new Intent(v.getContext(),ActivityTwo.class);
startActivity(intent);
}
});
if(savedInstanceState!=null){
mCreate=savedInstanceState.getInt(String.valueOf(mCreate));
mRestart=savedInstanceState.getInt(String.valueOf(mRestart));
mResume=savedInstanceState.getInt(String.valueOf(mResume));
mStart=savedInstanceState.getInt(String.valueOf(mStart));
}
// Emit LogCat message
Log.i(TAG, "Entered the onCreate() method");
mCreate++;
displayCounts();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
Save state information with a collection of key-value pairs
4 lines of code, one for every count variable
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt(String.valueOf(mCreate),mCreate);
savedInstanceState.putInt(String.valueOf(mRestart),mRestart);
savedInstanceState.putInt(String.valueOf(mResume),mResume);
savedInstanceState.putInt(String.valueOf(mStart),mStart);
}
Updates the displayed counters
This method expects that the counters and TextView variables use the names specified above
public void displayCounts() {
mTvCreate.setText("onCreate() calls: " + mCreate);
mTvStart.setText("onStart() calls: " + mStart);
mTvResume.setText("onResume() calls: " + mResume);
mTvRestart.setText("onRestart() calls: " + mRestart);
}
}
It looks like the problem is that you attempting to use values that have not been set yet when you try to capture the saved value.
All you need to do to fix it is to use the String constants that you have defined.
So, in onCreate(), you would have:
if(savedInstanceState!=null){
mCreate=savedInstanceState.getInt(CREATE_KEY);
mRestart=savedInstanceState.getInt(RESTART_KEY);
mResume=savedInstanceState.getInt(RESUME_KEY);
mStart=savedInstanceState.getInt(START_KEY);
}
Then, in onSaveInstanceState(), you would have:
savedInstanceState.putInt(CREATE_KEY,mCreate);
savedInstanceState.putInt(RESTART_KEY,mRestart);
savedInstanceState.putInt(RESUME_KEY,mResume);
savedInstanceState.putInt(START_KEY,mStart);

When Orientation change,onSaveInstanceState call caused values Swap

I have two variables to save on device orientation. One is current question number as an integer, another is a boolean value if the user cheated. It working fine when I'm storing and retrieving sinle value while storing both value it swaps.
public class QuizActivity extends ActionBarActivity {
// Logging members
private static final String LOG_TAG = QuizActivity.class.getSimpleName();
// The member of Saving the state for rotation of the device
private static final String KEY_BOOLEAN = "index";
private static final String KEY_INT = "index";
// Adding members
private Button mTrueButton;
private Button mFalseButton;
private Button mNextButton;
private Button mBackButton;
private TextView mQuestionTextView;
private ImageButton mImgRightButton;
private ImageButton mImgLeftButton;
private Button mCheatButton;
private TrueFalse[] mQuestionBank = new TrueFalse[] {
new TrueFalse(R.string.question_oceans, true),
new TrueFalse(R.string.question_mideast, false),
new TrueFalse(R.string.question_africa, false),
new TrueFalse(R.string.question_americas, true),
new TrueFalse(R.string.question_asia, true)
};
private int mCurrentIndex = 0;
// To save the CheatActivity returning result
private boolean mIsCheater;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(LOG_TAG, "QuizActivity onCreate(Bundle) called");
setContentView(R.layout.activity_quiz);
if(savedInstanceState != null) {
mCurrentIndex = savedInstanceState.getInt(KEY_INT);
mIsCheater = savedInstanceState.getBoolean(KEY_BOOLEAN);
}
}
// Not to loose activity state when rotating the device
#Override
public void onSaveInstanceState(Bundle saveInstanceState) {
Log.i(LOG_TAG, "onSaveIntanceState");
saveInstanceState.putInt(KEY_INT, mCurrentIndex);
saveInstanceState.putBoolean(KEY_BOOLEAN, mIsCheater);
super.onSaveInstanceState(saveInstanceState);
};
// to get the result from child activity(Cheat activity)
#Override
protected void onActivityResult(int arg0, int arg1, Intent data) {
if(data == null){
return;
}
mIsCheater = data.getBooleanExtra(CheatActivity.EXTRA_ANSWER_SHOWN, false);
};
}
You have the same keys!! Change code like this:
private static final String KEY_BOOLEAN = "index_BOOLEAN";
private static final String KEY_INT = "index_INT";
KEY_INT and KEY_BOOLEAN have the same name, the same value. So when setting those in the bundle one might overwrite the other. Use different names:
private static final String KEY_INT="intindex";
private static final String KEY_BOOLEAN="boolindex";

Easiest way to save data in savedInstanceState when managing an adapter(viewpager)

I'm working with an adapter(viewpager) and when the app changes orientation it loses its information. Which is the easiest way to conserve this information? I was going to use savedInstanceState inside the adapter but it doesn't recognise it.
Finally, I have done it following the advice of Jofre as he pointed in Activity restart on rotation Android
and looking in http://developer.android.com/intl/es/guide/topics/resources/runtime-changes.html
YOU MUST NOT MODIFY MANIFEST. DON'T ADD android:configChanges
SOLUTION:
//ALL THE VARIABLES YOU NEED TO SAVE IN YOUR ADAPTER PUT THEM AS PUBLIC, IE:
//public int a = 2;
//public String b = "a";
Public class Yourclass extends Activity{
Classofyouradapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.yourlayout);
final Save_object data = (Save_object) getLastNonConfigurationInstance();
adapter = new Classofyouradapter(your variables);
if (data != null) {
fillit(data);
}
myPager = (ViewPager) findViewById(R.id.yourpanelpager);
myPager.setAdapter(adapter);
}
#Override
public Object onRetainNonConfigurationInstance() {
final Save_object data = new Save_object();
return data;
}
public class Save_object{
int a = adapter.a;
String b = adapter.b;
//Rest of variables
}
public void fillit(Save_object data){
adapter.a= data.a;
adapter.b= data.b;
//Rest of variables
}
}

Immediate App Crash, whenever single line of code is added

Here is a class that works perfectly until I wanted to add one more feature, The code compiles then crashes immediately upon execution. The problem lies with the componentAnalyzer class that I wish to implement in this class. I donĀ“t know why it won't work because I implemented this componentAnalyzer in another class in the exact same way and it works beautifully.
I think its a small mistake but unsure. I commented out the part that was creating problems because the rest works and should not be touched.
The method that will use the componentAnalyzer is at the end of the code. I cut out everything that was working in order to see it easier.
public class PowerMonitorActivity extends Activity implements SeekBar.OnSeekBarChangeListener {
private static boolean instantiated = false;
//private static ComponentAnalyzer componentAnalyzer;
//private Context context;
private Button changeGPSButton;
private Button changeAudioButton;
private Button locationUpdateButton;
private SeekBar brightnessSeekBar;
private int screenBrightness = 123;
private Handler cpuHandler = new Handler();
private CPUMonitor cpuMonitor = new CPUMonitor();
private int updateTime = 1000;
private Handler totalPowerHandler = new Handler ();
private MediaManager mediaManager = new MediaManager();
private boolean requestingLocation = false;
private boolean wifiIsTransmitting = false;
private boolean wifiIsConnected = false;
private boolean cellIsTransmitting = false;
private boolean cellIsConnected = false;
private boolean isLogging = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Bundle extras = getIntent().getExtras();
if (!instantiated) {
instantiated = true;
//componentAnalyzer = new ComponentAnalyzer(context, extras);
}
// Create GPS button - note that location settings cannot be changed directly
// in a program. Rather, a settings screen is shown when this button is pressed.
changeGPSButton = (Button)findViewById(R.id.changeGPS);
changeGPSButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showGPSOptions();
}
});
totalPowerHandler.removeCallbacks(updatePower);
totalPowerHandler.postDelayed(updatePower, 1000);
}
private Runnable updateCpu = new Runnable() {
public void run() {
float util = cpuMonitor.getUtil();
int rutil = Math.round(100*util);
TextView cpuTextView = (TextView)findViewById(R.id.cpuTextView);
cpuTextView.setText(rutil+"%");
cpuHandler.postDelayed(this, updateTime);
}
};
private Runnable updatePower = new Runnable()
{
public void run()
{
//float testPower = componentAnalyzer.getWifiPower();;
TextView totalPowerView = (TextView)findViewById(R.id.totalPowerTextView);
//totalPowerView.setText(testPower+"mW");
totalPowerHandler.postDelayed(this, 1000);
}
};
Did you initialize context? In the current code example context is null when the ComponentAnalyzer is instantiated.
For my point of view, your application context is null (you forgot to assign reference to context for current activity or application)
Remove comments for problematic lines,
Now look at these lines,
Bundle extras = getIntent().getExtras();
if (!instantiated) {
instantiated = true;
componentAnalyzer = new ComponentAnalyzer(context, extras); // Here context is null
}
change this according to given below,
Bundle extras = getIntent().getExtras();
if (!instantiated) {
instantiated = true;
if(extras != null)
componentAnalyzer = new ComponentAnalyzer(PowerMonitorActivity.this, extras);
else Log.e("PowerMonitorActivity","Bundle extras is null");
}

Categories

Resources