Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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:

  1. Hole Nexus 7 in Portrait (it's fine if I hold tablet in Landscape)
  2. 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.

like image 732
Peter Avatar asked Oct 25 '14 15:10

Peter


People also ask

Why an activity is destroyed and recreated when you rotate your screen?

When you rotate your device and the screen changes orientation, Android usually destroys your application's existing Activities and Fragments and recreates them . Android does this so that your application can reload resources based on the new configuration.

Which attribute is used to set an activity screen to landscape orientation?

The screenOrientation is the attribute of activity element. The orientation of android activity can be portrait, landscape, sensor, unspecified etc. You need to define it in the AndroidManifest.

How do I force an app to stay in portrait mode?

Android Settings Start by going to Settings => Display and locate the “Device rotation” setting. On my personal cell phone, tapping this will reveal two options: “Rotate the contents of the screen,” and “Stay in portrait view.”


2 Answers

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.

like image 59
Simas Avatar answered Oct 08 '22 04:10

Simas


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.

like image 28
HB. Avatar answered Oct 08 '22 04:10

HB.