I need to apply different layouts for portrait and landscape orientations of my activity. Besides, I need to show alert if orientation is portrait.
I have specified android:configChanges="orientation|keyboardHidden" in AndroidManifest. I also override onConfigurationChanged method like this:
#Override
public void onConfigurationChanged(Configuration newConfig)
{
Log.d("tag", "config changed");
super.onConfigurationChanged(newConfig);
int orientation = newConfig.orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT)
Log.d("tag", "Portrait");
else if (orientation == Configuration.ORIENTATION_LANDSCAPE)
Log.d("tag", "Landscape");
else
Log.w("tag", "other: " + orientation);
....
}
While rotating from landscape to portrait log looks like:
config changed
Portrait
But while changing from portrait to landscape it looks like
config changed
Portrait
config changed
Landscape
Why onConfigurationChanged is called twice? How can I avoid it?
See my answer to another question here: https://stackoverflow.com/a/3252547/338479
In short, handling configuration changes correctly is hard to do. It's best to implement onRetainNonConfigurationInstance() which is called just before your application is about to be stopped and restarted due to a configuration change. Use this method to save anything you want ('this' is a good choice) and then let the system tear down your app.
When your app gets restarted with the new configuration, use getLastNonConfigurationInstance() to retrieve the state you just saved, and use it to continue your application without all that mucking about with bundles and shared preferences.
You can simply save the previous orientation and check if it has really changed.
If you set in AndroidManifest.xml android:configChanges to keyboardHidden|orientation for your activity, onCreate etc... won't be called. That makes the implementation significantly easier to implement. But of course layout will change from portrait to landscape as well.
Is there any particular reason you chose to handle rotation in this manner? While it is quicker since the activity doesn't get restarted on an orientation change, it isn't typically recommended, if I recall correctly. Another way to handle orientation changes is instead of overriding onConfigurationChanged(), overriding onCreate(), onStart() or onResume() such that
#Override
public void onStart() {
super.onStart();
int orientation = getWindowManager().getDefaultDisplay().getOrientation();
if(orientation == Configuration.ORIENTATION_PORTRAIT) {
Log.i(TAG, "Orientation is portrait");
// show whatever alerts here
}
}
and then specifying two layouts - one for portrait, one for landscape. The portrait version of the layout would remain at res/layout/whatever.xml, and the landscape version would live in res/layout-land/whatever.xml. The AndroidGuys had written a bunch of good articles on this topic, see http://androidguys.com/?s=rotational+forces&x=9&y=9
I'm pretty sure you would want to use onCreate rather than onStart. The only difference appears to be that onStart will get called when the application comes to the foreground. That wouldn't be a case where you'd want to make the user wait for you to re-initialize the UI. Otherwise, just change your setContentView call based on that if condition.
Android starts a new instance of your activity when changing orientation so using onCreate is the ideal method. You will have to save/restore your activity's data obviously in order to pick up where you left off - but you should be doing this anyway since any number of events can unfocus/kill your application.
Related
I am making an App which allow you read Wikipedia pages.
I want to display an icon each time when is phone is rotated from the portrait to landscape or vice versa. It will let user lock the screen orientation if he wants to or else the screen is oriented according to the sensor data. This is functionality is implemented by some of the App in the google play, for example - Pocket
To do this is i have overridden the
public void onConfigurationChanged(Configuration newConfig)
Now if i am setting the locked configuration by using( orientation_dir is the orientation value stored in the shared preferences and it is correct as i have debugged through the code for it.)
if(orientation_dir == Configuration.ORIENTATION_LANDSCAPE)
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
else if(orientation_dir == Configuration.ORIENTATION_PORTRAIT)
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
then orientation is set correctly but then onConfigurationChanged() method is not called when the phone is rotated.
If i set the orientation this way
if(orientation_dir == Configuration.ORIENTATION_LANDSCAPE)
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
else if(orientation_dir == Configuration.ORIENTATION_PORTRAIT)
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
then desired orientation is not set. Phone reset the orientation according to the sensor data.
I tried even by not calling the super in the method as i thought it might be setting it wrong but then it gives me the exception "Super not called".
I am trying for last 2 days and haven't got a any solution to this problem.
In general onConfigurationChanged() event fire only when an configuration change has occured. In your app the orientation changed event occurs only when the screen is free to rotate. If you have locked the screen orientation then the screen orientation event is not fired. onConfigurationChanged() does not listen to the sensor that is responsible to rotate the device but fires only when the appropriate event is happening.
So what you really want is to have access to a SensorManager and attach a SensorListener. This is the way for you to listen to the actual orientation of the device.
Here is a very nice demo that demonstrates the SensorManager capabilities with the orientation of the phone:
http://www.workingfromhere.com/blog/2009/03/30/orientation-sensor-tips-in-android/
UPDATE: The orientation sensor is a composite sensor to make things easier for the developer. It does not actually exist in the phone. Is a very neat sensor combining the accelometer sensor and the magnetic field sensor. And the OrientationSensor is currently deprecetated according to the docs (http://developer.android.com/guide/topics/sensors/sensors_position.html).
See What is the alternative to android orientation sensor? for sample usage.
it may need some fixing I have not tested it much.
onConfigurationChanged - is a notification to let your activity know the change in orientation.
You should not attempt to change or fix the orientation in that method. If you set the orientation to landscape or portrait then you will not get new orientation change notification because the orientation of the activity does not change. May be you should set the orientation setting in the event handler of the widget that you plan to show when there is a change in orientation.
Welcome all
I have a special need for my app. I must force the app to work only in portrait mode, but i need to know when the user has moved the phone to landscape mode. Why? because i am displaying a opengl view with a texture image, and when the user changues the phone position to landscape mode i must rotate the polygon without reseting the activity. Then i must force portrait mode on manifest, because i dont want that my onCreate method gets called again.
Please, can someone tell me how to achieve this?
I know how to rotate the image, i only need to know when the user has moved the phone to landscape position, but with portrait forced on manifest.
I tryed adding android:screenOrientation="portrait" in the manifest and also adding android:configChanges="keyboardHidden|orientation" to the declaration in the manifest; and then overriding onConfigurationChanged() in my activity. But this doens't works, because portrait mode is forzed, then onConfigurationChanged method is never called......
Thanks
Why not use the SensorManager to monitor when the phone has rotated 90 degrees. Actually this may be helpful also.
use this attribute in manifest android:configChanges="orientation" this stops recreating activity then override the onConfigurationChange() method. Give the same layout both in portrait and landscape mode. when orientation change occurs, that method wil be called then change the image as u like
Do Not set the screen orientation in the manifest (android:screenOrientation="portrait"). Add the android:configChanges="keyboardHidden|orientation", and override your onConfigurationChanged(). This way your onCreate will not be called twice.
Here a example of your onConfigurationChanged:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig); // tem que ter
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
}
}
I have the following problem: I have an image that I want to disappear when I change my phone from portrait to landscape. It works perfectly fine when I am on the current activity and I move orientations. It also works completely fine if I go to another activity and come back. But the problem is that after I return to my main page, onConfigurationChanged() will not be called the first time I change orientation. The image will show/not show correctly when I return, but when I first change the orientation after returning onConfigurationChanged() will not be called and the image will either stay/not stay until the second time I change the orientation. Any help you guys have would be extremely appreciated!
Here's a couple parts of my code. Ive put the configChange- orientation permission in the manifest already so thats not a problem.
#Override
public void onConfigurationChanged(Configuration newConfig) {L.p("configList",5200184);
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE&&isVertical==true) {
Logo.setVisibility(ImageView.GONE);
mainLogo.setVisibility(ImageView.GONE);
isHorizontal=true;
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT&&isHorizontal==true){
Logo.setVisibility(ImageView.VISIBLE);
mainLogo.setVisibility(ImageView.VISIBLE);
isVertical=true;
}
}
#Override
protected void onResume() {L.p("onResumeList", 5200113);
super.onResume();
Context ctx = getApplicationContext();
WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if((display.getOrientation() == Surface.ROTATION_90) || (display.getOrientation() == Surface.ROTATION_270))
{//Horizontal
L.p("you are resuming horizontal",5200124);
Logo.setVisibility(ImageView.INVISIBLE);
mainLogo.setVisibility(ImageView.INVISIBLE);
isHorizontal=true;
//isVertical=false;
}
else {//Vertical
L.p("you are resuming vertical",5200131);
Logo.setVisibility(ImageView.VISIBLE);
mainLogo.setVisibility(ImageView.VISIBLE);
isVertical=true;
// isHorizontal=false;
}
tracker.trackPageView("/deviceList");
}
Thanks!
No need to override orientation change. Just declare a new layout file in the layout-land folder that doesn't include the image (or in which the image is set to invisible/gone). When changing orientation, your activity will load that layout in onCreate.
Why do you check isHorizontal and isVertical?
Is it possible that one of those is false and that is causing it to fail the if conditional?
The onConfigurationChanged() method will not be called unless you declared the respective attributes under the <activity> in AndroidManifest.xml:
android:configChanges="orientation"
There is probably a flag somewhere causing the problem. And, we will probably never know what the problem is without seeing the full code, unfortunately.
But, please do not use configChange hacks. (https://plus.google.com/109306462100800920982/posts/LuYGURGdX7Q for a good explanation of the extremely rare case of when it is okay.)
Most likely, the onConfigurationChanged method does not need to be overridden at all here. Make a different layout for when the Activity is recreated on the configuration change.
I would like to know if it is possible to ask Android not to reload one Activity when orientation changes (I want to reload others but to kill this one !!).
I have checked the activity properties that I can set in the manifest but no one seems to allow that.
Thanks !
Try this:
public boolean onRetainNonConfigurationInstance() {
return true;
}
public onCreate() {
if(getLastNonConfigurationInstance() != null) {
finish();
}
}
It is simple, in your activity override onConfigurationChanged(Configuration config) and kill the activity inside of that.
Ex:
#Override
public void onConfigurationChanged (Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
finish();
}
This will cause the activity to be killed when a configuration change takes place. In the manifest under config changes select orientation for your activity. You can check which type of orientation it is changing to by looking at newConfig.orientation and compare it to the constants for portrait and landscape in the Configuration class.
I would like to know if it is possible to ask Android not to reload one Activity when orientation changes (I want to reload others but to kill this one !!).
Possible? Sure. A good idea? No. Users will get very confused if a simple twist of their wrist causes the current activity to go away. They might think that your app is broken.
Ideally, you allow users to use your activities in any orientation they desire. It is their device, not yours.
If, for some reason, some activity only makes sense in one orientation (e.g., landscape), use the android:orientation attribute in the <activity> element in the manifest to keep it in that orientation.
I want to make possible to use an activity in landscape / portrait. The activity starts with the layout for the current orientation (that means before starting the activity). After that it has to stick to it, and not react to orientation change.
I tried putting
android:configChanges="orientation"
in the manifest of the activity, and overriding
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
}
to do nothing (tried commenting the super call too, but this lead to exception)
but this has not the effect disabling the rotation change - the change is processed and the layout reconstructed, it just doesn't use the correct one.
And I can't use
android:screenOrientation
Because it seems I have to specify only one mode for always, and that's not what I need either.
And anyways, if I specify something there, the activity gets reconstructed when rotating.
Tried with
android:screenOrientation="nosensor"
that doesn't do anything
Here there's a lock of current orientation with code
http://www.samcoles.co.uk/mobile/android-lock-and-unlock-screen-orientation/
But it achieves the same effect as specifying orientation in XML (keeps layout but reconstructs the activity). It's a bit nearer to what I want (keeps orientation from start), but reconstructs the activity and I don't want it to react at all.
android:configChanges="orientation" doesn't work on the emulator at all, but it works fine on devices.
Try
#Override
public void onConfigurationChanged(Configuration newConfig) {
newConfig.orientation = getResources().getConfiguration().orientation;
super.onConfigurationChanged(newConfig);
}
Add this to onCreate
if (this.getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);}
else {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);}