5

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

Cruces
  • 2,703
  • 1
  • 24
  • 45

6 Answers6

13

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.

guness
  • 5,571
  • 7
  • 55
  • 82
  • This does indeed set screen orientation, unfortunatelly it set it for ALL screen sizes, my problem is that I want different orientation for different screen sizes for most activities, and the same orientation for one activity, from what I have searched, there is no way to do this through androidmanifest – Cruces Nov 19 '14 at 11:41
  • @Cruces check now mate. it is checkmate. – guness Nov 19 '14 at 12:03
  • 1
    yep that seems to be EXACTLY what I wish to do, thanks a lot man that really helped also this doesn't seem to be a hack solution, much cleaner than configChanges, and everyone and their mother has been warning me against using configChanges – Cruces Nov 20 '14 at 08:51
  • 3
    Didn't work for me. The `@integer/orientation` is always taken from the `values/` directory even on devices where I know it should fetch it from a more qualified directory like `values-sw600dp/`. The strange thing is that if you get the integer at runtime via `getResources().getInteger(..)` it DOES pick from the more qualified directory. To me it seems like a bug in the installer that parses `AndroidManifest.xml`. It does not search for best matching resource using qualifiers like `-swNNNdp` when finding integer resources. – Espen Riskedal Nov 27 '14 at 14:54
  • @EspenRiskedal interesting... Did you try on emulator too? and what is the device you are using for testing? – guness Nov 27 '14 at 17:08
  • @bluebrain I tried on Genymotion tablet and phone images running Android 4.3, and on Xperia Z3 and a Samsung Galaxy Tab 4 7.0. – Espen Riskedal Dec 01 '14 at 12:25
  • @EspenRiskedal did you find solution on your question? because i made same thing in my app(like sw600) it doesn't work @integer/orientation thing. – massaimara98 Dec 03 '14 at 09:50
  • @massaimara98 Sorry, I didn't find a solution that works in pure XML. I ended up using the `@integer/orientation` but calling a custom function from all my activities `onCreate(..)` that basically does `activity.getResources().getInteger(R.integer.device_orientation); activity.setRequestedOrientation(orientation);` – Espen Riskedal Dec 03 '14 at 10:59
  • @EspenRiskedal but as i know, its required 16 api level for setRequestedOrientation – massaimara98 Dec 03 '14 at 11:02
  • @massaimara98 no it's API 1 I believe http://developer.android.com/reference/android/app/Activity.html#setRequestedOrientation(int) – Espen Riskedal Dec 03 '14 at 11:03
  • @EspenRiskedal oo awesome – massaimara98 Dec 03 '14 at 11:05
  • 16
    This now gives a red-underline warning in Android Studio pointing out that you cannot use resource values in the Manifest that change between device configurations in this way. This makes a lot of sense since the Manifest is a static file in the APK so these references have to be resolved at build time. – Tunga Jan 18 '16 at 11:36
  • @Tunga can you please reconfirm? Because I don't see a warning on A.S 2.1.3 – guness Sep 19 '16 at 03:50
  • @guness I'm seeing it on Android Studio 2.2 (stable). Note that you must actually override the value in at least one variation to see the warning: http://imgur.com/JT1voCQ – Tunga Sep 21 '16 at 15:15
5

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! ;)

Crono
  • 1,902
  • 16
  • 16
  • 1
    This was a great solution for me. I used the `locked` orientation on the main activity of our app and used the `behind` orientation on activities that can be launched from there. It only requires setting the orientation once throughout the entire app. – Spencer May 03 '19 at 17:35
1

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.

Udo
  • 302
  • 2
  • 11
0

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.

  • No, I'm sorry it doesn't seem to work, it still destroys the original activity and restarts the activity from oncreate – Cruces Nov 19 '14 at 11:45
0

try this in your manifest.xml... this will stop the recalling the onCreate() multiple time while orientation changes...

android:configChanges="keyboardHidden|orientation|screenSize"
balaji koduri
  • 1,403
  • 9
  • 25
  • this seems to work, I think it's the screenSize operator that made the difference, I need far more testing than what I've done so far with this mini app I'm trying, but I think it's what I'm looking for, thanks for the answer, I'll try it – Cruces Nov 19 '14 at 11:48
  • in my case it works fine..., try it, if it is suitable with your requirement give a rating.. – balaji koduri Nov 19 '14 at 11:56
  • yes it does work, but from what I've researched configChanges is a bit of a no no to alter, still a solid solution, thanks a lot – Cruces Nov 20 '14 at 08:52
-1

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

John
  • 8,568
  • 7
  • 48
  • 82
  • the problem is, that the layouts for tablets are different to the ones for phone, the app is designed so that all layouts on tablet are viewed in landscape mode, and most layouts for phone are viewed on portrait mode, in order to implement portrait mode for tablets correctly and landscape for phones, it would take far too much time – Cruces Nov 19 '14 at 11:43