Activity created twice when called setRequestedOrientation() to display in Landscape mode - android

I have an app for Android, I want to force tablet (sw600dp and higher) to display in Landscape mode and phone to display in Portrait mode, so I handle in onCreate of my BaseActivity class
boolean isTablet= getResources().getBoolean(R.bool.isTablet);
if (isTablet) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
And the way I put "isTablet" in bools.xml file and put it in
values folder for phone
<resources>
<bool name="isTablet">false</bool>
</resources>
values-sw600dp for tablet
<resources>
<bool name="isTablet">true</bool>
</resources>
And in AndroidManifest I use
android:screenOrientation="nosensor"
just ensure to disable device orientation's sensor.
It seems to be my approach works fine (Landscape for tablet and Portrait for phone) BUT the problem happens when I run my app on Nexus 7 - my activities create twice. These steps are:
Hole Nexus 7 in Portrait (it's fine if I hold tablet in Landscape)
Then run the app
I find that the problem is the method setRequestedOrientation() (with 2 steps above). So I don't want to call that method anymore. I try to set orientation in AndroidManifest like:
android:screenOrientation="#integer/orientation"
Because:
SCREEN_ORIENTATION_LANDSCAPE = 0
SCREEN_ORIENTATION_PORTRAIT = 1
I declare "orientation" in integers.xml file and put it in
values folder for phone
<resources>
<integer name="orientation">1</integer>
</resources>
values-sw600dp for tablet
<resources>
<integer name="orientation">0</integer>
</resources>
Again, my approach tends to works fine BUT I find that AndroidMenifest just understands "orientation" in values folder, not in values-sw600dp folder. I don't want my activities to call 2 times. Did you have a problem like that?? Could you solve it? Thanks.

From the docs setRequestedOrientation(int):
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)
It's not being re-created, it's just being restarted to account for the change of orientation.
So just move the functionality that shouldn't be run twice to onCreate and you're done.

Simas answer is sort of correct, let me explain.
Let's say you are holding your device in a portrait position, you then start your Activity and in onCreate you call the following:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Then, you are basically telling the device it should rotate (since you are holding the device in portrait mode).
But if you hold the device in landscape before launching your Activity and call the same as above, your device doesn't need to rotate since it is already in landscape mode.
As we all know, rotating your device causes the Activity to be destroyed and created again. The same goes for when calling setRequestedOrientation (if the device is currently not in the requested position).
So.. How to deal with it.
The first and most obvious option would be to not call
setRequestedOrientation. Instead handle your rotation by using
onSaveInstanceState to store your values and
onRestoreInstanceState to restore the values that were stored in
bundle, etc..
In my case, because of the design of my application, I had to use
setRequestedOrientation because I'm rotating the device based on the
selected video dimensions.
Here is how I accomplished this.
Since I want to handle rotation myself, I first had to add the
following in my manifest:
android:configChanges="orientation|screenSize|keyboardHidden"
By doing this you are overriding configuration changes. As
mentioned in the docs - This technique should be considered a last
resort
Next, I created a different layout for when I want to rotate the
device to landscape and called the following:
private void rotateScreen(Uri vidUri) {
try {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
Bitmap bmp;
retriever.setDataSource(this, vidUri);
bmp = retriever.getFrameAtTime();
videoWidth = bmp.getWidth();
videoHeight = bmp.getHeight();
if (videoWidth > videoHeight) {
setContentView(R.layout.activity_video_player_land);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
if (videoWidth < videoHeight) {
setContentView(R.layout.activity_video_player);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
} catch (RuntimeException ex) {
Log.e("MediaMetadataRetriever", "- Failed to rotate the screen");
}
}
Since everything in my portrait layout is in my landscape
layout, I do not have to worry about resources not being found.
The solution I went with will not work for all applications (if you have different resources for different orientations) but in my case, I use all the same resource, resized and moved around to better fit the landscape view.

In my case My screen orientation in manifest was portrait. I have changed it to landscape
android:screenOrientation="landscape"
then remove the line
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
from the onCreate block
This solved my problem. Sometimes the answer might be that easy

Related

Google pixel android10 not supporting configChange from manifest

As my application supports only portrait mode for mobile devices.
As I select device Auto-rotate on.
But when I install this application on Google Pixel Android 10. It rotates in landscape mode.
As I mentioned in the manifest android:configChanges="screenLayout|keyboardHidden|screenSize|orientation".But still the WebView rotates in landscape mode.
How to handle this scenario.
Also when the device will rotate in landscape mode in onConfigurationChanged() method will return from the function.
Still, it rotates in landscape mode.
Please suggest to me.
Thanks
android:configChanges="screenLayout|keyboardHidden|screenSize|orientation"
fun onConfigurationChanged(){
if(Mobile){
return
}
Expected is The view should not rotate in landscape mode as it is supported for portrait mode only for the mobile devices.
In your manifest.xml file add following line to every activity declared: -
android:screenOrientation="portrait"
It will make sure that your application will be in portrait mode only.
android:configChanges="screenLayout|keyboardHidden|screenSize|orientation"
Above line will not prevent it to go to landscap mode. It will prevent view to regenerate and this how there is no need to save the states of the views.
To restrict app in portrait mode you should add below line in your activity tag.
android:screenOrientation="portrait"
Also the method onConfigurationChanged is called when configuration has been changed. Means after changing orientation it is being called so you can not write something inside of it to prevent activity to go into landscap mode.
Or you can try this
if(CommonUtils.dpFromPx(this, resources.displayMetrics.widthPixels.toFloat())>=600){
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
}
else{
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
}
and the mothod dpFromPx is:
public static float dpFromPx(final Context context, final float px) {
return px / context.getResources().getDisplayMetrics().density;
}

How to change screen orientation, without creating a new activity on android?

I do not know if the title is correct, here is what happens.
I have an application which works differently on a phone and on a tablet, on a phone it shows as portrait on a tablet it shows as landscape.
To achieve this I created a class called CoreActivity which is extended by all my activities and does the following:
public class CoreActivity extends Activity {
protected boolean _landscape = false;
public boolean isPhone() {
int layoutSize = getScreenLayoutSize();
return (layoutSize == Configuration.SCREENLAYOUT_SIZE_SMALL || layoutSize == Configuration.SCREENLAYOUT_SIZE_NORMAL);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isPhone() && !_landscape) {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
protected int getScreenLayoutSize() {
return (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK);
}
}
My problem occurs when I wish to show a screen on a phone setup on landscape mode, to do this I use the following:
#Override
protected void onCreate(Bundle savedInstanceState) {
_landscape = true
super.onCreate(savedInstanceState);
}
The problem is, that on a phone, if the user is holding the phone on portrait mode (as one would, since most of the application is in portrait mode) then the activity gets created and destroyed and then recreated. But if they are holding it on landscape mode, then it is only created once.
My problem occurs because on the onCreate method I launch the threads that load data, and I also show fragments.
Is there a way to avoid this problem? is there a way to launch an activity from the start on portrait mode and not change it, or have it not create twice?
Thanks in advance for any help you can provide
Recreating occurs just because you are forcing to, by calling setRequestedOrientation probably in order to set screen orientation. However you don't need to check and change it by code. You can do it via xml file. You can set different xml files depending on the screen size. But it is little bit hack so there is no guarantee in the future.
On the manifest file you can force by:
<activity
android:name="com.my.example.MyActivity"
android:screenOrientation="landscape"/> // or portrait
So as far as I understand you want to force portrait for small sizes and landscape(or sensor) for larger screen sizes. But above configuration applies for all screen sizes. Here is the tricky part: landscape portrait sensor etc. are all integers defined here.
As you might guess you can write android:screenOrientation=0 instead of landscape. What we know from beginning lessons of android, we can define integers in xml files then their values might vary on screen size. So..
You should first create different integers.xml files for different screen sizes. i.e.:
values
- integers.xml
values-large
- integers.xml
for values/integers.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="orientation">1</integer> // 1 for portrait
</resources>
for values-large/integers.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="orientation">0</integer> // 0 for landscape
</resources>
and finally you you have to manipulate manifest file by:
<activity
android:name="com.my.example.MyActivity"
android:screenOrientation="#integer/orientation"/> // read constant from xml files
You can also use sensor , fullSensor, nosensor, locked, behind, reverseLandscape, reversePortait options too. But I am warning you, this is a hack solution.
Well, I found a solution to this issue, just declare:
android:screenOrientation="locked"
on every activity having this issue in the manifest.
And keep using setRequestedOrientation() programatically to define if landscape or portrait orientation within onCreate() method,
It will work! ;)
If all your activites must have the same orientation on a device, you can start your application with a splash screen activity, set the orientation like in your current code and forward to your CoreActivity or any other activity in your App.
In your AndroidManifest.xml set
<activity
android:name=".CoreActivity"
android:screenOrientation="behind"/>
This will use the same orientation as the activity that's immediately beneath it in the activity stack.
Did you try adding android:configChanges="keyboard|keyboardHidden|orientation" to the <activity>-Tag inside of your AndroidManifest.xml?
This should prevent the system from restarting the Activity, but I am not sure whether this will actually work when forcing the orientation programatically. It's worth a shot though.
try this in your manifest.xml...
this will stop the recalling the onCreate() multiple time while orientation changes...
android:configChanges="keyboardHidden|orientation|screenSize"
You dont need to handle this manually. Android has built it support for different screen sizes
check this link
http://developer.android.com/training/multiscreen/screensizes.html

It is possible to known when the screen orientation is changed but with portrait mode forced on manifest?

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) {
}
}

Kill an activity when orientation changes

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.

Handling activity rotating in Android

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.

Categories

Resources