I have stumbled on a problem, that, when the screen turns off while being in LANDSCAPE orientation, certain devices "rotate" the app back to PORTRAIT position (because the lockscreen is PORTRAIT only or something like that). I did a little research before posting this, and most popular work-around is to modify app's configuration change process to prevent activity being recreated after the configuration has changed.
But disabling activity recreation is not a solution for me, because my app supports both orientations with sepparate layout's etc.
So i would like to find out, is it possible to disable the configuration change only in special cases (Screen turned off and orientation is landscape)? Or is the right way to override onConfigurationChanged() then manually manage activity recreation inside that function (i guess simply setting different layout resources when orientation is changed simply wont cut it)?
Or is the right way to override onConfigurationChanged() then manually manage activity recreation inside that function?
Yes to an extent.
You cannot set the configChanges attribute programmatically. I guess it's to do with the way an Activity is created. They're created from the XML first and then the overridden methods in your activity implementation are invoked. There's nothing in the API that lets you change the configChanges attribute.
Now in your case it doesn't sound like you need to. If you support both orientations, then if the user locks the device and it rotates back why does it matter? From a UX perspective we know it's in portrait mode again. So should your app when it opens back up.
Related
I tried to solve this problem, searched through the Internet, no real answer was found.
I'm developing an app where the YouTube player is needed. This player is the YouTubePlayerSupportFragment since it's in a support fragment (so it's also nested). After the initial setup I realized that whenever I rotate the phone, the video stops playing and it has to be restarted again. This is obviously not what I want.
Then I found some SO answers (like this) where people say that the Activity needs to handle the config changes, so I added android:configChanges="keyboardHidden|orientation|screenSize" to the Activity in the manifest. This solved the problem, the video now keeps playing even on orientation change and the full-screen rotation doesn't look ugly. Cool, I said, only to realize that this messed up big time the other parts of the app because the config is now being updated after all the views are in place. This means that if my phone was in portrait mode and I rotated it to landscape, the layout being used was still going to be the portrait one.
I found solutions for this suggesting calling setContentView(...) in the Activity's onConfigurationChanged(...) and reinflating the view in the Fragments, but this seems to be a rather cumbersome if not terrible solution as It's not just a simple content setting I need, the fragments need to be retained (e.g. scroll position in RecyclerView) too. The built-in setRetainInstance(true) does not work in this case as the view would be recreated with that either, but the config is still the old one when the onCreateView(...) is being called.
It would be nice if I could catch the configChanges events if the user is on that screen (fragment) only but retain Activity recreation anywhere else.
Don't suggest using more Activities, I cannot use a separate Activity for this screen and the rest of the app because of UI/UX reasons.
As per this YouTube Android Player API Guidelines
It is encouraged that you handle configuration changes caused by
orientation in your activity manually, to avoid recreating this
fragment's view every time the configuration changes. For the best
user experience, you should also manually handle the fullscreen event
by changing the layout of your activity.(See the second approch)
As you are already handling on configuration change on your own, I can see two possible solutions of your problem.
Set setFullscreenControlFlags (To your YouTubePlayer object) to FULLSCREEN_FLAG_ALWAYS_FULLSCREEN_IN_LANDSCAPE (This will causes the player to automatically enter fullscreen whenever the device enters landscape orientation.) in conjunction with FULLSCREEN_FLAG_CONTROL_ORIENTATION(To enable automatic control of the orientation.) flag.
Note that this flag should only be set if your activity is locked in
portrait (and is specified as such in the manifest).
The flag is useful if you don't have a landscape layout for your
activity, but would like to enable landscape orientation solely for
fullscreen video watching.
This approach might solve your problem and it is also suggested by official documentation as I mentioned above. In setFullscreenControlFlags method set FULLSCREEN_FLAG_CUSTOM_LAYOUT, that disables the default fullscreen layout handler, enabling you to control the transition to fullscreen layout manually. As well as enabling you to implement a custom fullscreen layout, this option also provides the advantage of avoiding the rebuffering that occurs in the default fullscreen behavior.
An application implementing custom fullscreen behavior should ensure
two things
That the player's view takes up the whole available space of
application's window whenever onFullscreen(boolean) is called. That
the activity is not recreated when the orientation changes to
landscape. To achieve this for an activity that supports portrait, you
need to specify that your activity handles some configuration changes
on its own in your application's manifest, including orientation,
keyboardHidden and screenSize.
See here on how to use this flag.
As per the first link I shared, this second approach will avoid recreating fragment's view every time the configuration changes. Also you don't need to call setContentView(...) in onConfigurationChanged(...).
Hope this will help you.
Whenever I use setRequestedOrientation(int) it behaves differently from when I declare the orientation in my Manifest.xml.
(this is expected)
I read that (from docs):
If the activity is currently in the foreground or otherwise impacting the screen orientation, the screen will immediately be changed (possibly causing the activity to be restarted)
Practically this means that whenever an app is started, while the device has an orientation that is NOT the orientation that will be set with setRequestedOrientation(int), the activity will be created twice (once 'normally' and once to reflect requested orientation).
As of now it is not worthwhile to make my activites 100% config-change-proof, what I would like is a way to set the requested orientation, in code, without having to create my activities twice. Is there a way?
(Preferably without using hackish workaround such as setting the 'orientation' flag in configChanges)
EDIT:
Accepted answer is right, it simply isn't logical (doesn't make sense). For new readers, what I did was add a stub-activity (mainly empty activity that doesn't do much). All it does is use getRequestedOrientation() when it differs from what I want it to be, I will call setRequestedOrientation(int), otherwise start the activity I want and in its onCreate also call the setRequestedOrientation(int) to keep it in requested orientation.
No, that doesn't make sense. If you set the orientation programmatically, the Activity is already running before you can do anything to change the duplicate creation for each orientation.
I got an app that is locked in landscape orientation. Now, when I change the devices settings to set its orientation locked to portrait, some problems occur.
After a bit of testing, it seems that for each Activity that is started, the onCreate is called twice.
First time for portrait orientation, second time as an orientationChange with orientation set to landscape. The first orientation is wrong, and probably has something to do with the device being locked to portrait.
In the app, the orientation is forced to landscape programmatically (using setRequestedOrientation), and I prefer to keep it that way, if possible, for various reasons.
Any ideas about how to avoid this behavior?
Thanks in advance!
Ok, I found a solution myself.
After a lot of searching and digging in the code, the solution was fairly simple.
All I had to do was add:
android:configChanges="orientation|screenSize"
... to all my Activities in the manifest file.
This tells the app that I will handle configuration changes myself in the code. Instead of doing this, I didn't add any handlers for these config changes. This way, my Activities aren't recreated when the orientation change happens at the creation of those Activities. I can do it this way, because my app is locked in a certain orientation.
This post came closest to my problem, but it's solution didn't work for me:
Android: set activity orientation BEFORE onCreate, but not in manifest (HDMI plugged in issue)
This post gave me the answer:
http://www.acnenomor.com/1053172p1/oncreate-were-called-twice-after-implementing-setrequestedorientation
Try setting up the orientation directly in the manifest instead of programmatically. Under your activity tag in AndroidManifest.xml add android:screenOrientation="landscape".
This should force the activity to be directly created in the correct orientation.
Background
Each time the device is being rotated, Android will destroy the current activity and re-create it with the new configuration.
An easy way to avoid activity re-creation is by adding "configChanges" values to the manifest ("screenSize" and "orientation" as I recall).
The problem
If you use the "configChanges" attribute, the app won't respect the orientation lock feature that some (or all?) Android devices have, which prevent anything from being rotated when the screen is being rotated.
What I've tried
I tried playing with the "screenOrientation" attribute values, yet none of them achieved what I wanted.
The question
How can I prevent the activity from being re-created when the screen changes its orientation, while also respecting the user preference of orientation-lock?
Is it perhaps possible to get the value of this preference, so that I could let the activity lock its orientation when it's being set?
OK, never mind. I think I just missed the correct one:
android:screenOrientation="user"
Together with the other configChanges values, this works perfectly.
I was wondering why not use android:configChanges="keyboardHidden|orientation" in every (almost every ;)) activity?
Goods:
no need to worry about your activity been rotated
it's faster
Not so nice:
need to change your layouts if they are depending on screen size (e.g. layouts with two columns or so)
Bad:
no flexible way to have different layouts on different orientation
not so good when using fragments
But if we don't use different layouts, why not?
Quick Background
By default, when certain key configuration changes happen on Android (a common example is an orientation change), Android fully restarts the running Activity to help it adjust to such changes.
When you define android:configChanges="keyboardHidden|orientation" in your AndroidManifest, you are telling Android: "Please don't do the default reset when the keyboard is pulled out, or the phone is rotated; I want to handle this myself. Yes, I know what I'm doing"
Is this a good thing? We shall soon see...
No worries?
One of the pros you start with is that there is:
no need to worry about your activity been rotated
In many cases, people mistakenly believe that when they have an error that is being generated by an orientation change ("rotation"), they can simply fix it by putting in android:configChanges="keyboardHidden|orientation".
However, android:configChanges="keyboardHidden|orientation" is nothing more than a bandaid. In truth, there are many ways a configuration change can be triggered. For example, if the user selects a new language (i.e. the locale has changed), your activity will be restarted in the same way it does by an orientation change. If you want you can view a list of all the different types of config changes.
Edit: More importantly, though, as hackbod points out in the comments, your activity will also be restarted when your app is in the background and Android decides to free up some memory by killing it. When the user comes back to your app, Android will attempt to restart the activity in the same way it does if there was some other configuration change. If you can't handle that - the user will not be happy...
In other words, using android:configChanges="keyboardHidden|orientation" is not a solution for your "worries." The right way is to code your activities so that they are happy with any restart Android throws at them. This is a good practice that will help you down the road, so get used to it.
So when should I use it?
As you mentioned there is a distinct advantage. Overwriting the default configuration change for a rotation by handling it yourself will speed things up. However, this speed does come with a price of convenience.
To put it simply, if you use the same layout for both portrait and landscape you're in good shape by doing the overwrite. Instead of a full-blown reload of the activity, the views will simply shift around to fill the remaining space.
However, if for some reason you use a different layout when the device is in landscape, the fact that Android reloads your Activity is good because it will then load up the correct layout. [If you use the override on such an Activity, and want to do some magical re-layout at runtime... well, good luck - it's far from simple]
Quick Summary
By all means, if android:configChanges="keyboardHidden|orientation" is right for you, then use it. But PLEASE be sure to test what happens when something changes, because an orientation change is not the only way a full Activity restart can be triggered.
From my point of view: If the layout is the same in both landscape and portrait mode - you might aswell disable one of the two in your app.
The reason why I state this is that I as a user expect the app to provide me with some benefit, when I change orientation. If it doesn't matter how I hold my phone, then I don't need the choice.
Take for instance an app where you have a ListView, and upon clicking a ListItem you want to be shown a detailed view for that item. In landscape you would od this by dividing the screen in two, having the ListView on the left and the detailed view on the right. In Portrait you would have the list in one screen and then change the screen to the detailed view when a ListItem is selected. In that case orientation change makes sense as well as different layouts.
I don see why.... occasional restarts are ok in my opinion... configChanges handles most cases for me... well maybe in some types of applications this can be problem but it depends really on type of app and how you restore state when app restarts... When one of my app restarts user is logged back and last activity opens by my code and user jus loses some steps to go back where he was but not big deal.. In other some state is always persisted and some state is always restored on restart. When activity restarted it had to be that app have not been used or something... so no problem at all... In game for example this can be problem maybe or in some other type of app I don't know...
I say that when you do it this way applications just works fine under normal circumstances. And code is much more readable without ton of logic needed for saving and restoring where u just can make new bugs and have to maintain it all the time... sure if android gets out of power and kill you application window it lose the context and starts again, but this happen just in special situations and on newer devices I belive this is more and more rare...
So kill me, but I use this across applications quite successfully...
android:configChanges="locale|keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
But I understand that for some special kind of applications it may be not good way but most of apps can live with this just OK.
Yeah I think pausing will make it quicker than releasing the player. Still have the pause though.
Have now found a solution that won't pause the song.
State in the manifest that you will handle the config change for screen orientation and then use the onConfigurationChanged method to load the layout file. By doing this in logCat I can see onPause, onCreate & onResume aren't called, and therefore the song isn't paused.
update the manifest to handle the orientation.
android:configChanges="orientation|screenSize"
add this code
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
setContentView(R.layout.activity_main);
}