I have an Android app with an activity that processes the orientation change (android:configChanges="keyboardHidden|orientation" in the manifest). It also has an onConfigurationChanged handler that calls the superclass.
After the device is rotated, the activity remains in portrait mode. And the whole screen is in bizarre state where the X axis goes physically bottom to top, the Y axis goes left to right, the status bar runs along the left screen edge, and all text goes physically up. It's as if the system is forced to not acknowledge the orientation change.
What I would really like to do, I'd like to avoid activity restart, but process the orientation change with few carefully placed layout property flips. However, in the abovementioned state of the GUI I cannot do that. Reloading the main layout file makes no change.
Question - how do I tell the system to switch physical orientation, so that XY axes go the way they should?
EDIT: and here's a curious data point: on all onConfigChanged calls, the newConfig.orientation is 1.
You really shouldn't use android:configChanges. This technique is considered as a last resort. Please read Handling Runtime Changes for more details.
Brief explanation: if you used android:configChanges its your responsibility to handle configuration change event and reload the UI resources for new configuration. When onConfigurationChanged() is called, getResources() already points to correct resources from new configuration. You only need to manually re-set all layouts, strings, dimensions, drawables, etc. with new (potentially changed) values.
You also didn't mention reasons why you decided to go with configChanges, instead of normal Activity workflow. This might have been useful to give you some alternatives.
The attribute android:screenOrientation="portrait" in the manifest was to blame. With this attribute present, even letting the system restart the activity won't switch the screen to true landscape mode.
Related
I need to prevent restarting the activity when the user changes the orientation, so I need to set:
android:configChanges="orientation"
But in the document, there this a note on orientation,
Note: If your application targets Android 3.2 (API level 13) or
higher, then you should also declare the "screenSize" configuration,
because it also changes when a device switches between portrait and
landscape orientations.
I'm a little afraid of using with screenSize together because I only need that for orientation.
I'd like to know when the screenSize event will occur?
I set 'orientation|screenSize' together and tested with changing device's font size, but the screenSize is not changed so the activity has been reloaded.
When(in what case) the screenSize event will be called? and is there any side effects if I set the screenSize to configChanges?
I looked at the Android source code for this. The interesting bits are in ActivityRecord method crossesSizeThreshold and getConfigurationChanges. The screenSize event occurs when the dimensions of the screen changes and the change might be "important" for the application. So what does "important" mean:
When a screen resize happens for an app, Android tries to decide if the activity needs to be relaunched. If the size change is small a re-layout of the activity content might be enough, while for a bigger resize a full configuration change needs to occur.
To decide if the configuration change has to occur Android collects the app's size-sensitive resource qualifiers (e.g. layout-h400dp). If the resize crosses a qualifier boundary a configuration change occurs, while if the resize does not cross the boundary the activity is kept and only a re-layout gets executed.
Having said that, I tried to reproduce this behavior. I couldn't come up with a conclusive test because other configChanges events happened during the resize too.
My initial point still stands. It's hard to predict all possible reasons why a configuration change might occur and trying to prevent the recreation of the activity is very difficult to do. Especially with the amount of API versions and device models we have today. A well architected app that separates business logic and state from the UI layer, is still the way to go.
I have a service that overrides onConfigurationChanged.
It's getting called when you change orientation from portrait -> landscape and vice versa but the problem is when you are rotating from landscape -> landscape. When you are tilting your phone to the Left then you change it to the Right.
As said on many answers here on stackoverflow the manifest file should be:
android:configChanges="keyboardHidden|orientation|screenSize"
Changing orientation from side to side (Left and Right) results in the same screen size thus onConfigurationChanged never gets called.
My app relies on the accelerometer so I need to get the current orientation to adjust my values.
Any thoughts on how and why onConfigurationChanged doesn't get called?
Any thoughts on how and why onConfigurationChanged doesn't get called?
Because that's not considered to be a configuration change. Configuration changes are for where Google thinks that you will need different resources. Since the screen is the same size after the rotation as before, and since nothing else resource-wise is different, they do not consider this to be a configuration change.
I have a WebView embedded in a Fragment. In the manifest file, I have declared that the activity will handle orientation changes:
android:configChanges="orientation|screenSize"
and in the Activity, I have over-ridden onConfigurationChanged() in order to capture the orientation.
I thought this means that we have to explicitly take care of any changes in the screen orientation. But what I see is that the screen is still rotated (although the activity is not re-created).
If I use the following line:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
it does prevent the screen from being rotated, but I don't get the rotation event.
So, in short, I don't want the system to rotate the screen, and at the same time, I want to get an event from the system that the orientation has changed from portrait to landscape.
Thanks,
Rajath
If you override onConfigurationChanged(Configuration newConfig), you should be able to handle the changes.
Thanks for editing the question, what you're after is now clear to me. I've got two suggestionsScreen orientation (i.e. portrait, landscape, reversePortrait, reverseLandscape, etc) just depends on orientation of the device in 3D space. So one idea is to capture the 3D orientation of the device yourself, which is the same information that the operating system uses to make the screen orientation decision. This means that you need to capture the accelerometer and the magnetic field sensor readings. One example of capturing that information is in my answer to Android Compass that can Compensate for Tilt and Pitch.Alternatively, you might try setting up a dummy activity that exists purely to capture the screen orientation information. That activity could sit on the activity stack behind your main activity. Although I'm not sure whether activities that aren't on top of the activity stack are notified of screen orientation changes.
My application is bitmap intensive, with pixel-exact layout (it's a sort of game, actually, and it's pretty hard to avoid this pixel-based coordinates).
What I wanted to do is to perform some layout calculations and bitmap pre-scaling in my onCrete - I use well known API - getWindowManager().getDefaultDisplay().getSize() - to retrieve the screen size and do my calculations.
However, I've just hit an unexpected problem. My activity is configured as landscape only, but if I start my application on emulator and onCreate() is called while the emulator is locked, the screen size returned by getSize() indicates portrait orientation. Once I unlock the screen, onCreate() is called again, this time correctly in line with expected landscape mode dimensions.
I'm not sure how to handle this situation. I see the following options:
for each onCreate() call perform full layout calculation and resource scaling again. This is the logically correct solution, but I don't want to the same work twice, just to throw away the first result.
if onCreate() is called for portrait mode, just do nothing, and set black background (I can see there's a silly rotate animation when I unlock the screen, so this would become pretty much a fade-in animation)
Actually I'd prefer second option, but I'm slightly afraid of any side-effects. Anyone faced this problem?
Update (2012-07-08):
I've probably assigned a slightly misleading title to this question (sorry!), as the problem is not in retrieving the dimensions itself, nor calculating the layout. It's more about the activity being first created in portrait mode, and then recreated in landscape mode again, despite being declared as landscape-only. I initially expected (reasonably, huh?) the activity to be created in landscape orientation only.
I eventually decided to fill the activity with black color when it's created in portrait mode, no side effects observed. On Android 4.0 I can see actual rotation animation when I unlock the screen - a bit strange, but well, I guess it is supposed to inform the user that she should rotate the phone. Given that in portrait mode I just fill the screen with black color, this animation looks sort of like a fade-in and rotation combined - perfectly acceptable.
Use that
DisplayMetrics dm=new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(dm);
Using this(Look code at down) only gives you screen size and if your views has static size they will be seen in different size on every different screen.
Display screen=getWindowManager().getDefaultDisplay().getSize();
How to use:
every screen has diffrent density. So use:
float density=dm.density;
with this density, you can set your views size like that:
(YOUR_ITEM_SIZE)*density;
also look here for additional information:
http://developer.android.com/reference/android/util/DisplayMetrics.html
if the emulator is locked , can't you assume that the user can't run anything anyway , so the app doesn't need to handle this end case ?
anyway , as bmavus wrote , use getMetrics for getting the screen size . also , if you need to change the screen orientation of the app , you can do so either in the manifest or in code.
for games , i would advice using opengl solutions , and if you don't have much time digging for it , you can use third party engines that can help you , such as andengine and libgdx.
I encountered weird problem when changing screen orientation rather fast, or when something heavy goes on background. When I call setContentView(R.layout.main);on onConfigurationChanged (I handle orientation changes myself),after screen is rotated android for a brief moment sets layout for opposite to orientation. For example - when you change orientation layout changes like this Portrait>Landscape, but sometimes, in my case, it goes like this Portrait>Portrait(when phone is already in in landscape position)>Landscape.
Sometimes you dont even notice this, and sometimes screen shrinks to about 1/3 for a second.
Well, It's not really a big deal, but in my activity I have Coverflow widget (based on Gallery) and to make it look good on most of the screens I set image sizes based on parent container size (in onSizeChanged of widget), and when orientation changes goes as described above coverflow widget picks up a wrong size.
The only way I see now is to either call onCreate on orientation change (Which I cant do, because of heavy UI populated online), or set a delay on initializing UI (which is ugly).
So I wonder, is there any callback of setContentView() or anything else, so I could know when layout is actually ready, so I can init UI.
Or maybe there is another way around?
PS: For some reason this glitch mostly occurs on Desire HD.
AndroidManifest.xml
android:configChanges="orientation"
Is it what you expect?