I am an Android Beginner. According to the lifecycle of an android application, when screen orientation is changed following methods are called:
onPause()
onStop()
onDestroy()
OnCreate()
onStart()
onResume()
But I have now added onConfigChanged in my XML file. When activity starts, onCreate, onStart and onResume are called. But when my screen orientation changes, only onConfigurationChanged method is called, the above mentioned methods are not called as shown below:
Any reason for this?
Thanks in advance.
Normally when an orientation , language , ... change happen the activity get destroyed and restarted and start the lifecycle from the begining unless you override the onConfigurationChanged function.
More details from Android documentation:
Configuration Changes
If the configuration of the device (as defined by the
Resources.Configuration class) changes, then anything displaying a
user interface will need to update to match that configuration.
Because Activity is the primary mechanism for interacting with the
user, it includes special support for handling configuration changes.
Unless you specify otherwise, a configuration change (such as a change
in screen orientation, language, input devices, etc) will cause your
current activity to be destroyed, going through the normal activity
lifecycle process of onPause(), onStop(), and onDestroy() as
appropriate. If the activity had been in the foreground or visible to
the user, once onDestroy() is called in that instance then a new
instance of the activity will be created, with whatever
savedInstanceState the previous instance had generated from
onSaveInstanceState(Bundle).
This is done because any application resource, including layout files,
can change based on any configuration value. Thus the only safe way to
handle a configuration change is to re-retrieve all resources,
including layouts, drawables, and strings. Because activities must
already know how to save their state and re-create themselves from
that state, this is a convenient way to have an activity restart
itself with a new configuration.
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.
It's a very good thing that only onConfigurationChanged() is called with orientation changes. It's actually preferred because it means that your initializations in onCreate() DON'T have to happen again -- you can reuse them with the new views that you rebind in onConfigurationChanged(). This results in a faster application that uses less memory and is less clunky.
Case in point:
You have a ListView. That ListView uses an ArrayAdapter. In onCreate(), you find the listView using findViewById(R.id.xxx) and you CREATE a NEW ArrayAdapter and set it for that listView. If every time onCreate() is called when the orientation changes, you would be creatting a new ArrayAdapter each and every time the orientation changes. Imagine switching the orientation 3 times -- what a waste!
Like this, you can create the ArrayAdapter in onCreate(), once, ever (when your application is created). And when the orientation changes, in onConfigurationChanged(), simply reset the ArrayAdapter for the new ListView you pick up again using findViewById(R.id.xxxx). Done. Only 1 ArrayAdapter has ever been created and it's data remains in tact for the new orientation.
Beautiful! :)
Related
What is the significance of:
super.onCreate(null);
instead of
super.onCreate(savedInstanceState);
With this change, I am able to avoid many problems that otherwise plague my Activitys each time a configuration change occurs (rotation, locale shift, permission toggle). It seems that with this change, the Activity is started afresh whenever a configuration change triggers it to restart. And I don't seem to lose any data or process state by doing this: all my Activitys are restored exactly to their former state.
My question is, can I do this with impunity henceforth, or am losing something in the bargain? I don't really understand why this works, whether it is safe or not, and what unintended effects it may have on my app.
I chanced upon this trick here.
Related Questions:
Calling super.onCreate() with null parameter?
Will 'Bundle savedInstanceState' be alive after Application is being killed?
Activity state instance - insights?
Activity's instance state: what is automatically stored and restored
onCreate() call first when activity is about to create, Also Android System manage activity lifecycle and can kill the activity with saving its instanceState, in case if acitvity out of focus for user for long time and system is on low memory situation.
An activity has essentially four states
super.onCreate(null) : Would always create activity as it is creating fisrt time , even Android system provide its savedInstanceState, and does't matter what orientation configurations are.
super.onCreate(savedInstanceState) : Activity can use 'savedInstanceState' to reset its state or component where it was last.
To achive this, acitivty's instance state need to be persist before activity lost user attention( that could be onStop or onDestroy)
savedInstaceState can also be important to handle if activity configuration got changed, Please check acitvity life cycle behavior on Configuration change
am losing something in the bargain?
Only if you are working with Fragments. see Calling super.onCreate() with null parameter?
Yes, onCreate(...) is necessary to start an Activity, but passing Bundle as an argument is required when you are working with fragments.
What did you infer from that?
The argument savedInstanceState is anyway null by default. So you aren't really losing anything in a bargain.
But wait, we usually use Bundles to maintain orientation change, right?
the following manifest code declares an activity that handles both the screen orientation change and keyboard availability change:
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name">
Now, when one of these configurations change, MyActivity does not restart. Instead, the MyActivity 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.
the following onConfigurationChanged() implementation checks the current device orientation:
#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();
}
}
But Remember: When you declare your activity to handle a configuration change, you are responsible for resetting any elements for which you provide alternatives. If you declare your activity to handle the orientation change and have images that should change between landscape and portrait, you must re-assign each resource to each element during onConfigurationChanged().
As far as I know a lot of data is saved in the bundle savedInstanceState.
E.g. all the views' states in your current layout, such as the current content of any EditText or CheckBox.
You could also look up some official sources to check whether you need to keep some data.
Here's a nice article about it
Basically it says that all View class implements the methods onRestoreInstanceState and onSaveInstanceState, which are saving and restoring any temporary states they were in before the state change.
The savedInstanceState is a reference to a Bundle object that is passed into the onCreate method of every Android Activity. Activities have the ability, under special circumstances, to restore themselves to a previous state using the data stored in this bundle.
It is very important to use savedInstantState to get values from Intent which is saved in the bundle.
All your data stored in class variables or local variables is lost whenever you change rotation of device, but in your activity it looks like you have not stored any data as long as user enters any data, but instead you are perhaps reading data on click of a button or something like that, your activity will behave and work normally, and all user inputs like text inside EditText will be restored by Android itself, because it identifies "IDs" (android:id="#+id/anyID") allotted to each view and can restore by itself all the values inserted by user.
I hope this this helps you...
Happy coding :)
How does android restart an activity or fragment when rotating the app?
I'm interested in the methods or flags it uses in the process. Thx
When any configuration changes, such as device orientation takes place the activity will be destroyed and recreated that is unless you've modified this process inside the manifest file. As #Lazai mentioned, if you change activity configuration changes functionality, you must handle manually loading any new resources required for the new orientation, that includes, styles, themes, drawables, and layouts inside of the callback Activity.onConfigurationChanged(Configuration newConfig).
Note: if you don't indicate inside of the manifest file that you'd like to manually handle configuration changes, you will never received a call to Activity.onConfigurationChanged(Configuration newConfig).
Android exports recommend not handling the configuration changes yourself and letting the OS handle itself. So how to know when orientation changes are taking place when you don't get calls to onConfigurationChanged(Configuration newConfig)? Well if you're are targeting above API Level 11, their is a handy method on the Activity class that indicates if activity is experiencing the a configuration change, called Activity.isChangingConfigurations(). This method will always return false until the activity is preparing to be destroyed. It will have a valid value prior to the call Activity.onPause(), that you can check and determine if your device is rotating and your app should perform some special optimizations or state saving procedures.
I personally recommend letting the system handling the config changes and checking if the orientation is changing, because in a large app or complex activity it can get very tedious reloading the necessary resources and assets just to prevent an activity from discarding a simple object or during rotations.
When your orientation changes all the fragments and activities are destroyed , and the views are re-created again ; unless you change the config settings :
<activity android:name=".SampleActivity"
android:configChanges="orientation|keyboardHidden">
So basically the key here is onStop() and onDestroy() , you should save the states of your tasks when rotating in the onStop() method (or even onPause()) to restart them again when the views are loaded (onResume()).
See more here link
When Activities and Fragments rotate, they are destroyed (with onDestroy()) then they go through the same lifecycle as they were created.
in your fragment override onconfigurationchanged method
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
// reload your views here
}
In the onCreate() of my MainActivity, my app does an intensive operation to generate some data set (runs in a separate thread, but takes some 2 - 3 seconds to complete normally). Now my problem is that, when orientation changes, the app again does this complex computation again.
Since I haven't done anything like this before, I was wondering if there is a way around this. My first thought was to store the computed data in a static variable, so that the data is persisted between different instances of MainActivity. I am guessing this is not the best approach.
My data set consists of a Map and an ArrayList and not a simple data type, if it helps.
I have looked at the onSaveInstanceState(), but it only provides to store values like int, String, etc.
In addition to what #Raghunandan suggested you can read the official docs on Recreating an Activity .
It says:
Your activity will be destroyed and recreated each time the user rotates the screen. When the screen changes orientation, the system destroys and recreates the foreground activity because the screen configuration has changed and your activity might need to load alternative resources (such as the layout.
It also introduces the concept of
onSaveInstanceState()(To save additional data about the activity state, you must override this method) and
onRestoreInstanceState() method (The default implementation of this method performs a restore of any view state that had previously been frozen by onSaveInstanceState(Bundle)).
You can also see the sample implementation of these methods here Saving Android Activity state using Save Instance State thread, which will help you to save and restore the state.
Update
You may also try using:
<activity name= ".YourActivity" android:configChanges="orientation|screenSize"/>
The docs for android:configChanges say;
It lists configuration changes that the activity will handle itself. When a configuration change occurs at runtime, the activity is shut down and restarted by default, but declaring a configuration with this attribute will prevent the activity from being restarted. Source: How to save state during orientation change in Android if the state is made of my classes?
Hope this helps.
For online games, it would be great to know if an Android Activity's onDestroy() is only called because Android is going to re-create it (e.g. device rotation) or if the user opted to exit the game.
My plan was to set a flag in the Activity's onSaveInstanceState() when Android is probably re-creating the Activity:
private boolean mDestroyedForReCreation;
...
protected void onSaveInstanceState() {
...
mDestroyedForReCreation = true;
}
If you did this, you can check mDestroyedForReCreation in onDestroy():
If the flag is set (true), don't dismiss the user from the online game.
If the flag is not set (false), dismiss the user from the online game as he did voluntarily exit the game.
Is that a correct approach? And if yes, is it recommended or is there any better solution? I hope so because I don't really like that solution ...
I suggest you to remove such kind of game logic from activity's life cycle. Create a Service. If no one binded - all activities are dead. Is someone binded - keep working.
If you do not want to create service, you can use onRetainNonConfigurationInstance method. Here is example.
You should use onRetainNonConfigurationInstance because it is called by the system, as part of destroying an activity due to a configuration change, when it is known that a new instance will immediately be created for the new configuration. onSaveInstanceState called when android going to kill activity and maybe restore it sometimes or maybe not ).
You can simply avoid restarts on rotation by handling this configuration changes by code. You can do this in your Manifest.xml like this:
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
android:label="#string/app_name" >
So your app won't restart on rotation and if the keyboard opened/closed.
I think this solution is much simpler.
In this case you almost don't need to handle onSaveInstanceState() for exiting, except you start another intent/activity where you need to save your game state. Note that a phone call will also interrupt your code. I know some games with funny bugs where the time is resetted but not the score.
I would just simplify the whole thing, and set a flag that is toggled when the user exits the game, something like:
void exitGame() {
mUserExited = true;
finish();
}
(Or you might need more logic if you need to destroy multiple activities)
Then check the flag in onDestroy().
Whatever logic you have about configuration changes (rotation, etc.) will have nothing to do with the exit game flag.
Also, remember that the 'back' button's default behavior is to finish() the current activity (if nothing else is above it) - that won't count as an "exit" in this case. The behavior here is up to you.
Activity has a method called isFinishing() that is probably what you are looking for.
See: https://stackoverflow.com/a/9621078/445348
If you need to know this, you should consider handling rotation and other configuration changed events yourself rather than letting the system do it. If you set in your manifest that the activity handles configChanges, it will call onConfigChange when it rotates rather than destroying and recreating the activity. A large amount of apps do this, the whol destroying and recreating on rotation thing Android does is absolutely retarded.
onRestoreInstanceState() will be called if when it is restored /recreated , if the activity if killed by android it saves its activity UI state and some values you can override onSaveInstanceState
but because onSaveInstanceState() is not guaranteed to be called, you should use it only to record the transient state of the activity (the state of the UI)—you should never use it to store persistent data. Instead, you should use onPause() to store persistent data (such as data that should be saved to a database) when the user leaves the activity. Also onRestart will be called after onStop() when the current activity is being re-displayed to the user. So probably you can save your state in onPause / if onRestart is called it is like it is being re displayed , while if onCreate is called without onRestart it is recreated . Other solution is to use singleInstance and override method onNewIntent which is called if activity is not destructed but like restarted on a new intent .
When using the onPause method in the Android SDK, that code is run whenever the Activity was re-drawn (Such as rotating the device). Is there a way to detect whether the Activity was actually paused (Such as a new window popping up) or if the Activity was actually just re-drawn?
Actually if you look at the life cycle of an activity, when the device is rotated, the activity is restarted, so after onPause(), the activity goes through the complete restart cycle (onStop() and onRestart() are also called), so in this case you can set some value depending on what functions were called, or check the device's orientation.
Also when the activity goes into background, onPause() is called, and when the activity is no longer visible to the user, onStop() is called, which are due to specific reasons, the application can check that by setting some variable. For complete understanding, study the activity life cycle (Alternate Link)
But why do you need to know what happened to the activity? By overriding appropriate functions and providing proper layout resources, you do not need to know what happened in most cases.
For orientation, you can also get the orientation using getRotation method.