Switch keeps checked after orientation change, even if I set checked false programmatically.
Here is a example code:
public class MainActivity extends AppCompatActivity {
Switch sw;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sw = (Switch)findViewById(R.id.sw);
sw.setChecked(false);
System.out.println(sw.isChecked());
}
}
The sout prints false, but the switch keeps checked on the interface. This is the switch xml element in layout file:
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/sw"
android:checked="false"/>
What am I missing?
The reason your checkbox is not checked on Orientation Change is that Android fires Activity methods on Orientation Change like so:
onPause -> onSave -> onStop -> onCreate -> onStart -> onResume
If you want sw.setChecked(false); to fire on Orientation Change place it in your Activities onResume() function like so:
//Other Code Above, i.e. onCreate();
#Override
public void onResume(){
super.onResume();
// Put your code here...
sw.setChecked(false);
}
There are also other options to prevent a restart of the Activity per this Android Documentation under Configuration Changes
In some special cases, you may want to bypass restarting of your
activity based on one or more types of configuration changes. This is
done with the android:configChanges attribute in its manifest. For any
types of configuration changes you say that you handle there, you will
receive a call to your current activity's
onConfigurationChanged(Configuration) method instead of being
restarted. If a configuration change involves any that you do not
handle, however, the activity will still be restarted and
onConfigurationChanged(Configuration) will not be called.
restarted.
And Finally another Option via onSaveInstanceState(Bundle savedInstanceState) and onRestoreInstanceState(Bundle savedInstanceState):
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean("YourCheckBox", enable);
super.onSaveInstanceState(savedInstanceState);
}
And retrieve it using this method:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
boolean mychkbox = savedInstanceState.getBoolean("YourCheckBox");
}
More generally you probably want to override following so that you can preserve state like this when orientation changes (and activity re-created)
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SOME_BOOL_VALUE, boolVar);
}
and read it back then in onCreate if savedInstanceState is set
Related
I am using onStop() to save a boolean value which I need when the activity resumes.
Here is my code:
#Override
protected void onStop()
{
super.onStop();
Bundle bundle = new Bundle();
bundle.putBoolean("value",value);
getIntent().putExtras(bundle);
}
#Override
protected void onResume()
{
super.onResume();
if(getIntent().getExtras() != null)
{
Bundle bundle = getIntent().getExtras();
value = bundle.getBoolean("value");
}
}
My issue is no matter what the value of the boolean is, my onResume() always retrieves it as FALSE. This issue only occurs if I leave my activity using the BACK button. If I press home, things seem to work fine(i.e if the boolean was TRUE then onResume() retrieves it as TRUE.
Please do help me because I don't understand why onResume() always gets the value of the boolean as FALSE even when I save it as TRUE in onStop().
I also tried onRestart(), onPause() and onBackPressed() but I still can't get the proper boolean value to be saved.
You have two issues here.
the correct way to save values during activity destruction is to use onSaveInstanceState(Bundle) and get the value from the Bundle passed to onCreate(Bundle).
Check example below:
public class SavedInstanceExample extends AppCompatActivity {
private boolean myBoolean;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_savded_instace_example);
if (savedInstanceState != null) {
myBoolean = savedInstanceState.getBoolean("key");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("key", myBoolean);
}
}
When you press the back button the activity will be finished. That means completely gone. And values saved one the methods explained above will not be there.
The way to save something to survive the Activity being finished is to save it to the disk. One common/simple way to do it is using the SharedPreferences
When the Android application opens the following activity lifecycle methods will be called.
onCreate();
onStart();
onResume();
and when you press the back button, the application will be destroyed by calling following methods
onPause();
onStop();
onDestroy();
And in the second case when you press home button the following methods will be called
onPause();
onStop();
That means your application is not destroyed completely and you can open it from recent apps so that the activity re-appears by calling
onStart();
onStop();
That is why your code works in this case.
Activity gives onSavedInstanceState() method to save your data during configuration changes or something else.
Here is the link for Android documentation for
Activity
I would suggest you to read the Google Developers Link for Activity documentation.Google Developers Activity
The OP's code is basically right. onSavedInstanceState is no good if you are not destroying the activity but, for example, replacing a fragment in an activity with another fragment and then returning to it, in which case you have to use onStop and onResume as follows. This is Kotlin and it works but the principle is the same.
override fun onStop() {
super.onStop()
val bundle = Bundle()
bundle.putBoolean("BOOL", false)
activity?.intent?.putExtras(bundle)
}
override fun onResume() {
super.onResume()
if (activity?.intent?.extras != null) {
val bundle = activity?.intent?.extras
val bool = bundle?.getBoolean("BOOL")
println("BOOL is $bool")
}
}
My Java's a bit rusty but I suspect the OP's problem might have been that he mixed up boolean and Boolean?
Here is my GamePlay Activity code
public class GamePlay extends Activity implements OnClickListener {
private boolean disableSound = false;
//.....
//Code Code
//.....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//.....
//Code Code
//.....
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putBoolean("disableSound", disableSound);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
disableSound = savedInstanceState.getBoolean("disableSound");
Menu menu = (Menu)findViewById(R.menu.tic_tac_toe);
MenuItem toggleSoundItemMenu = menu.findItem(R.id.toogle_sound_menu);
if(disableSound)
toggleSoundItemMenu.setTitle(R.string.toggle_sound_off_label);
else
toggleSoundItemMenu.setTitle(R.string.toggle_sound_on_label);
}
//other functions and code
}
Now on game restart I am restarting the activity. Following code is inside the onClickListener() withing appropriate case
case R.id.game_play_restart_button:
Intent restartActivity = new Intent(this,GamePlay.class);
finish();
startActivity(restartActivity);
break;
But still the state does not persist. I disable the sound and restart the game then sound turns back on which is the default behavior. What am I missing? Any suggestion is appreciated.
The savedInstanceState bundle is kept by the system as long as the activity hasn't been destroyed by the system.
When you call finish, you destroy the current activity, and the bundle that comes with it.
That's the reason why you can't get your boolean back.
You should consider passing this boolean as an extra in the intent like:
restartActivity.putExtra("disableSound", disableSound)
And then on the onCreate of your activity:
getIntent().getBooleanExtra("disableSound", false)
Please note that the last parameter false is just a default value. You can set it to true if that's the behaviour you want.
Iam little bit amazed with this.I have an onResume() in my activity.Its called and works well in my emulator, but in a physical device samsung galaxy note for specific with jellybean installed,its not called.Instead onCreate() is called all the time.Why this happens?
public void onResume(){
super.onResume();
if(firsttime){
try {
Toast.makeText(getApplicationContext(), "Resuming Activity",Toast.LENGTH_LONG).show();
addReminder();
} catch(Exception exception) {
exception.printStackTrace();
}
} else {
firsttime=true;
}
}
This is my code.firsttime is a static boolean variable.It is used to prevent onResume() being called when app is started for the first time
Considering your current scenario, you should save variable in preferences instead of relying on activities lifecycle since lifecycle depends on many things.
Using static variable for this scenario is bad choice in general.I think this should solve your problem.
Try to print something inside the onResume and check it in LogCat.... the code inside onResume may be causing this.
or else can you elaborate your question?
I think here is what happens,
when your app not the Top app, the activity manager actually destroy the activity, it only called
public void onSaveInstanceState(Bundle savedInstanceState)
no
onStop
called, so no
noResume
will be called.
The correct to do this is, when put all states of this activity when
public void onSaveInstanceState(Bundle savedInstanceState)
called.
and in your onCreate() function, do such thing
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
to check if you have some saved state.
Most code was copy from android developer site:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
I have an Android Activity with Frgment. When my application is started, a listview is loaded with 10 elements which are sent from a server. (simple request).
When i change the orientation of my device, the activity is recreated, i see also the spinner with my request to load my listview.
How can i do to forbid re-creation of Activity ?
I already set the flag :
android:configChanges="orientation|keyboardHidden|screenSize"
And onConfigurationChanged :
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
You then want to override
#Override
public void onConfigurationChanged(Configuration newConfig)
{
}
in your activity, with what you want to do on orientation/keyboardHidden/screenSize.
Setting the flag in the manifest tells the app that you want to handle those configuration changes yourself.
You need to override onSaveInstanceState(Bundle savedInstanceState) and keep state of all the values that you need when orientation changes.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putString("jsonArrayString", jsonArrayStrin);
// etc.
}
This value will be passed to the onCreate and/or onRestoreInstanceState. You can retrieve this using following :
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// This bundle has also been passed to onCreate.
String myArrayString = savedInstanceState.getString("jsonArrayString");
}
Hope this helps
If you don't need the orientation to change, you can also prevent it in the manifest. Just specify in the activity element the attribute: android:screenOrientation
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.)
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.
// 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.