What's the right way to save instance state only on rotation? - android

I understand that when a device rotates, Android destroys and recreates the current activity in order to load orientation-specific resources. To save state, I can use onSaveInstanceState(Bundle outState)and the regular onCreate(Bundle savedInstanceState) but this saves and restores state each time the app is destroyed/created for any reason.
What I want to do is to save/restor state only when the app was destroyed/created because of an orientation change; when the app is destroyed because of memory or the user kills it, I'm not interested in saving state. ¿How can I do this?

You could set the onConfigurationChange() method. To do that you need to override it in your Activity's code and set a few parameters in your Manifest:
MainActivity.java
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
You have to add these attributes (android:configChanges="orientation|screenSize") to your activity, set as many as you want to handle:
AndroidManifest.xml
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name">
Be careful, with this setup, your activity will not restart, as mentioned in the docs, so, if you want to restart it you will need to implement a manual restart.
Now, when one of these configurations change, MyActivity does not
restart. Instead, the MyActivity receives a call to
onConfigurationChanged().
Link to the main documentation.

Turns out my question was wrong from the beginning.
When the device rotates, Android calls onSaveInstanceState(Bundle outState) and onRestoreInstanceState(Bundle savedInstanceState) as a way for the developer to save/restore state. When the activity is destroyed via back button or finish(), onSaveInstanceState is not called and the savedInstanceState bundle that's passed to onCreate() is null. So trying to answer the "was this created after a rotation or not?" question is irrelevant.
Posted in case someone has the same question and thanks to all that took time to read and help.

Related

How to prevent restarting from orientation change?

Here is the structure of my application.
MainActivity.java calls FragmentActivity.java,
FragmentActivity.java calls GameView.java
GameView.java calls Thread.java.
Basically all the gaming logic will be handled by GameView and its thread.
I don't know how to prevent from restarting the game when there is a orientation change.
If i paused the thread and resume it, the app crashes and also i can not use onSaveInstanceState method in Gameview.java
Any help?
It is completely possible through the Android manifest.
Just add in the activity declaration, in which you want to disable the restarting the following attribute:
android:configChanges="orientation|screenSize"
Then you can overwrite the onConfigurationChanged() in your activity and you get the callback which event just happened. In your case the orientation change. And with this approach the activity doesn't restart, when your orientation changes.
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
You are looking for onResume() and on pause() ... You store values into a bundle in pause and instantiate those values on the resume method and show a dialog as this happens to prevent the user from noticing the obvious.
You can have some control over what happens on orientation change, by defining an Application class in your manifest file, and overriding public method onConfigurationChanged().
Base class for those who need to maintain global application state.
You can provide your own implementation by specifying its name in your
AndroidManifest.xml's tag, which will cause that class
to be instantiated for you when the process for your
application/package is created.
You just need to check for newConfig == Configuration.ORIENTATION_LANDSCAPE and such. At this point you might want to reload resources to get things working.

Rotation restarts activity

I have a problem with my android app. My activities restart when I rotate my phone (onCreate is called). I have googlet and have tried
android:configChanges="keyboardHidden|orientation"> in my manifes, but with no luck. Can someone please explain to me how I can get this to work
EDIT: I find out that i nedd to ad these codes
manifest
<activity
android:name="?"
android:label="#string/?"
android:theme="#style/?"
android:configChanges="orientation|screenSize">
MainActivity
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
In your Activity, you can override the method onSaveInstanceState. You can save the information you need into a Bundle. That bundle will be passed in to the onCreate method after the orientation has changed. If you would rather just specify one orientation to be used, within your manifest file, either under the application tab or activity tag, place:
android:screenOrientation="portrait"
You can try android:configChanges="keyboard|orientation|screenSize">. However, be aware that restarting the Activity on configuration change is normal behavior. Unless you have very specific needs, you should not be using configChanges.

What Android event is only called once until the activity is destroyed?

I'm looking for a single answer (but I might be asking the wrong question)
Question- does any event only get called once TOTAL until an activity is destroyed?
I ask because when my user rotates the phone to landscape oncreate and onstart are both invoked causing a reload of sorts.
I'm looking for an event that I could put behavior into that would only get run 1x (until the activity is killed)
Thank you in advance
If it is specific to the Activity just check your savedInstanceState parameter in the onCreate event. If it is null, run your code, if not, your code has already been run.
Example:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(savedInstanceState == null) {
// Run your code
}
}
savedInstanceState will always be null when onCreate is run for the first time, and it will be populated thereafter.
You don't really specify what you're trying to do with it, so I can't guarantee this is appropriate for your use, but Application.onCreate is only called once.
If you want to eliminate the recreation of your activity on an orientationchange you can listen for configchanges in the manifest.
<activity
android:name=".MyActivity"
android:configChanges="orientation" >
</activity>
And then you can override onConfigurationChanged like so:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged( newConfig );
LinearLayout main = (LinearLayout) findViewById( R.id.mainLayout );
main.requestLayout();
}
to recreate the layout so that it matches the new orientation, without recreating the entire activity.
Check http://developer.android.com/guide/topics/resources/runtime-changes.html to handle configuration changes and to maintain your huge data between them...if all you need to maintain between the configuration change is just the settings,you can use the onSavedInstanceState() and onRestoreInstanceState() callbacks and the given bundles.

Android configuration changed

I'm interested to know which methods are overridden, when an Android device is rotated (i.e. when configuration changes)?
onSaveInstanceState(...), onConfigurationChanged(...), onRestoreInstanceState(...) - something similar to this?
It will be also interesting for me to listen about the whole process connected with changing a configuration. Thanks.
According to the android developer reference you have to use:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
For more information see: http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
You could be interested in seeing: http://developer.android.com/guide/topics/manifest/activity-element.html#config
Here you can find all configuration listener you can listen.
Remember to put them in the android manifest:
<activity
android:configChanges=["orientation"]
. . .
</activity>
Hope this helps...
When you rotate the device your Activity will re-create and all the variables will be re-initialized. So, in that case if you want to some values to remain same on Rotation also you can store their state using the onSaveInstanceState() and you can restore in onCreate() again by checking Bundle is not null.
if(savedInstanceState != null){
// get the restore value from the Bundle
}
Where as onConfigurationChanged() will be called when you rotate the Device(Note that this will only be called if you have selected configurations you would like to handle with the configChanges attribute in your manifest). From the parameter you will get the new device configuration.
If you don't want your Activity to get re-created on rotation of Device then you have to add this line to your activity tag in the AndroidManifest file.
android:ConfigChanges="keyboardHidden|orientation"
From android developers...
To retain an Object during a runtime configuration change:
Override the onRetainNonConfigurationInstance() method to return the Object you would like to retain.
When your Activity is created again, call getLastNonConfigurationInstance() to recover your Object.
Android calls onRetainNonConfigurationInstance() between onStop() and onDestroy() when it shuts down your Activity due to a configuration change. In your implementation of onRetainNonConfigurationInstance(), you can return any Object that you need in order to efficiently restore your state after the configuration change.
A scenario in which this can be valuable is if your application loads a lot of data from the web. If the user changes the orientation of the device and the Activity restarts, your application must re-fetch the data, which could be slow. What you can do instead is implement onRetainNonConfigurationInstance() to return an object carrying your data and then retrieve the data when your Activity starts again with getLastNonConfigurationInstance().
Look at here for more info Retaining an Object During a Configuration Change you can also find example over their..
Thanks..
Go to Manifest and add:
android:configChanges="orientation|screenSize"
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"
android:configChanges="orientation|screenSize"
/>
In Main Activity: Copy and Paste this code:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
All Done -

Activity lifecycle - onCreate called on every re-orientation

I have a simple activity that loads a bitmap in onCreate. I find that if I rotate the device I can see from the logs that onCreate called again. In fact, because all instance variables are set to default values again I know that the entire Activity has been re-instantiated.
After rotating 2 times I get an FC because not enough memory can be allocated for the bitmap. (Are all instances of the activty still alive somewhere? Or does the GC not clean up fast enough?)
#Override
public void onCreate(Bundle savedInstanceState) {
File externalStorageDir = Environment.getExternalStorageDirectory();
File picturesDir = new File(externalStorageDir, "DCIM/Camera");
File[] files = picturesDir.listFiles(new FilenameFilter(){
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".jpg");
}});
if (files.length > 0) {
Bitmap bm = BitmapFactory.decodeStream(new FileInputStream(files[0]));
ImageView view = (ImageView) findViewById(R.id.photo);
view.setImageBitmap(bm);
}
}
From all that I read, onCreate should be called once during the lifetime of an application. Am I wrong about this? How can re-orienting the device cause the activity to be recreated?
android:configChanges="keyboardHidden|orientation|screenSize"
Caution: Beginning with Android 3.2 (API level 13), the "screen size"
also changes when the device switches between portrait and landscape
orientation. Thus, if you want to prevent runtime restarts due to
orientation change when developing for API level 13 or higher (as
declared by the minSdkVersion and targetSdkVersion attributes), you
must include the "screenSize" value in addition to the "orientation"
value. That is, you must decalare
android:configChanges="orientation|screenSize". However, if your
application targets API level 12 or lower, then your activity always
handles this configuration change itself (this configuration change
does not restart your activity, even when running on an Android 3.2 or
higher device).
From docs: http://developer.android.com/guide/topics/resources/runtime-changes.html
What happen when orientation changed
Life Cycle of orientation
onPause();
onSaveInstanceState();
onStop();
onDestroy();
onCreate();
onStart();
onResume();
---- app recreated and now is running ---
If you do long operation in onCreate() and want prevent re-create your activity add configChanges attribute in your mainfest
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name">
screenSize if you targeting api >= 13
Activity is recreated after each rotation by default. You can override this behaviour with configChanges attribute of the activity tag in AndroidManifest. For further details and different options, see http://developer.android.com/guide/topics/resources/runtime-changes.html
Actvity Lifecycle when you rotate screen
onPause
onSaveInstanceState
onStop
onDestroy
onCreate
onStart
onRestoreInstanceState
onResume
If you want to prevent FC from not enough memory, you need to deallocate resources in onStop() or onPause(). this allows you to use fresh memory in onCreate().
This is an alternate solution to preventing the recreation of the activity by using
android:configChanges="keyboardHidden|orientation"
As sometimes your activity's layout is different in portrait and landscape (layout, layout-land).
preventing recreate on orientation change will prevent your activity from using the other orientation's layout.
Yes, activity's onCreate() is called everytime when the orientation changes but you can avoid the re-creation of Activity by adding configChanges attribute of Activity in your AndroidManifest file in the activity tag.
android:configChanges="keyboardHidden|orientation"
On Create method will call everytime when you do orientation, to avoid this you have to use
//Define Below in you Manifest file.
<activity
android:name="com.ecordia.activities.evidence.MediaAttachmentView"
android:configChanges="keyboardHidden|orientation|screenSize"
</activity>
//Define Below in your activity.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
//your code
} else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//your code
}
}
It will works like a charm!!
Manifest XML activity Tag:
android:configChanges="keyboardHidden|orientation"‍‍‍
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
}
Use the above code to perform changes related to orientation in your Activity Java Code
Cheers!!!
One of the most common and suggested “solutions” to dealing with orientation changes is to not deal with them. You can do this by setting the android:configChanges flag on your Activity in AndroidManifest.xml as shown below:
<activity
android:name=".MyActivity"
android:label="#string/title_my_activity"
android:configChanges="orientation|screenSize|keyboardHidden" />
This is NOT the correct way to deal with orientation changes.
CORRECT way is to implement the onSaveInstanceState method (this could be in your Activity, Fragment or both) and place the values you need to save in the Bundle argument that gets passed to the method.
It is nicely described here: http://code.hootsuite.com/orientation-changes-on-android/
While it may seem a bit tedious to implement, handling orientation changes properly provides you with several benefits: you will be able to easily use alternate layouts in portrait and landscape orientations, and you will be able to handle many exceptional states such as low memory situations and interruptions from incoming phone calls without any extra code.
While the Manifest way may work, there is a better and proper solution for these types of problems. The ViewModel class. You should have a look here: https://developer.android.com/topic/libraries/architecture/viewmodel
Basically, you extend the ViewModel class and define all the data members in it which we want to be unchanged over re creation of the activity (in this case orientation change). And provide relevant methods to access those from the Activity class. So when the Activity is re created, the ViewModel object is still there, and so are our data!
Kindly see my way of doing it:-
http://animeshrivastava.blogspot.in/2017/08/activity-lifecycle-oncreate-beating_3.html
snippet is:-
#Override
protected void onSaveInstanceState(Bundle b) {
super.onSaveInstanceState(b);
String str="Screen Change="+String.valueOf(screenChange)+"....";
Toast.makeText(ctx,str+"You are changing orientation...",Toast.LENGTH_SHORT).show();
screenChange=true;
}
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
ctx=getApplicationContext();
if(!screenChange) {
String str="Screen Change="+String.valueOf(screenChange);
// ...
}
}
I had the same problem, in which my onCreate is called multiple times when the screen orientation is changed. My problem got solved when i add android:configChanges="orientation|keyboardHidden|screenSize" in the activity tag in manifest
I had the same problem and I did some workaround
Define didLoad boolean variable with false value
private boolean didLoad = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
if (!this.didLoad){
// Your code...
this.didLoad = true;
}

Categories

Resources