In my Android application, when I rotate the device (slide out the keyboard) then my Activity
is restarted (onCreate
is called). Now, this is probably how it's supposed to be, but I do a lot of initial setting up in the onCreate
method, so I need either:
onCreate
is not called again and the layout just adjusts oronCreate
is not called.转载于:https://stackoverflow.com/questions/456211/activity-restart-on-rotation-android
Using the Application Class
Depending on what you're doing in your initialization you could consider creating a new class that extends Application
and moving your initialization code into an overridden onCreate
method within that class.
public class MyApplicationClass extends Application {
@Override
public void onCreate() {
super.onCreate();
// TODO Put your application initialization code here.
}
}
The onCreate
in the application class is only called when the entire application is created, so the Activity restarts on orientation or keyboard visibility changes won't trigger it.
It's good practice to expose the instance of this class as a singleton and exposing the application variables you're initializing using getters and setters.
NOTE: You'll need to specify the name of your new Application class in the manifest for it to be registered and used:
<application
android:name="com.you.yourapp.MyApplicationClass"
Reacting to Configuration Changes [UPDATE: this is deprecated since API 13; see the recommended alternative]
As a further alternative, you can have your application listen for events that would cause a restart – like orientation and keyboard visibility changes – and handle them within your Activity.
Start by adding the android:configChanges
node to your Activity's manifest node
android:configChanges="keyboardHidden|orientation"
or for Android 3.2 (API level 13) and newer:
android:configChanges="keyboardHidden|orientation|screenSize"
Then within the Activity override the onConfigurationChanged
method and call setContentView
to force the GUI layout to be re-done in the new orientation.
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.myLayout);
}
What you describe is the default behavior. You have to detect and handle these events yourself by adding:
android:configChanges
to your manifest and then the changes that you want to handle. So for orientation, you would use:
android:configChanges="orientation"
and for the keyboard being opened or closed you would use:
android:configChanges="keyboardHidden"
If you want to handle both you can just separate them with the pipe command like:
android:configChanges="keyboardHidden|orientation"
This will trigger the onConfigurationChanged method in whatever Activity you call. If you override the method you can pass in the new values.
Hope this helps.
I just discovered this lore:
For keeping the Activity alive through an orientation change, and handling it through onConfigurationChanged
, the documentation and the code sample above suggest this in the Manifest file:
android:configChanges="keyboardHidden|orientation"
which has the extra benefit that it always works.
The bonus lore is that omitting the keyboardHidden
may seem logical, but it causes failures in the emulator (for Android 2.1 at least): specifying only orientation
will make the emulator call both OnCreate
and onConfigurationChanged
sometimes, and only OnCreate
other times.
I haven't seen the failure on a device, but I have heard about the emulator failing for others. So it's worth documenting.
what I did...
in the manifest, to the activity section, added:
android:configChanges="keyboardHidden|orientation"
in the code for the activity, implemented:
//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
//get views from ID's
this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);
//etc... hook up click listeners, whatever you need from the Views
}
//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
InitializeUI();
}
//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
setContentView(R.layout.main);
InitializeUI();
}
You might also consider using the Android platform's way of persisting data across orientation changes: onRetainNonConfigurationInstance()
and getLastNonConfigurationInstance()
.
This allows you to persist data across configuration changes, such as information you may have gotten from a server fetch or something else that's been computed in onCreate
or since, while also allowing Android to re-layout your Activity
using the xml file for the orientation now in use.
It should be noted that these methods are now deprecated (although still more flexible than handling orientation change yourself as most of the above solutions suggest) with the recommendation that everyone switch to Fragments
and instead use setRetainInstance(true)
on each Fragment
you want to retain.
onConfigurationChanged is called when the screen rotates. (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
What part of the manifest tells it "don't call onCreate()
"?
Also, Google's docs say to avoid using android:configChanges
(except as a last resort).... But then the alternate methods they suggest all DO use android:configChanges
.
It has been my experience that the emulator ALWAYS calls onCreate()
upon rotation.
But the 1-2 devices that I run the same code on... do not. (Not sure why there would be any difference.)
Update for Android 3.2 and higher:
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 declareandroid: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).
Instead of trying to stop the onCreate()
from being fired altogether, maybe try checking the Bundle
savedInstanceState
being passed into the event to see if it is null or not.
For instance, if I have some logic that should be run when the Activity
is truly created, not on every orientation change, I only run that logic in the onCreate()
only if the savedInstanceState
is null.
Otherwise, I still want the layout to redraw properly for the orientation.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_list);
if(savedInstanceState == null){
setupCloudMessaging();
}
}
not sure if this is the ultimate answer, but it works for me.
I just simply added
android:configChanges="keyboard|keyboardHidden|orientation"
in the manifest file and did not add any onConfigurationChanged
method in my activity.
So every time the keyboard slides out or in nothing happens.
The approach is useful but is incomplete when using Fragments.
Fragments usually get recreated on configuration change. If you don't wish this to happen, use
setRetainInstance(true);
in the Fragment's constructor(s)
This will cause fragments to be retained during configuration change.
http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)
Add this line to your manifest :-
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
and this snippet to the activity :-
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}