1

I am having trouble setting up landscape mode in my application.

I have a /res folder that contains a layout folder and a layout-land folder

layout
-----main.xml

layout-land
-----main.xml

My /layout-land/main.xml contains different UI elements than /layout/main.xml. How can I map each layout appropriately when the user has switched to landscape mode and vice versa?

I am basically displaying a full screen ImageView when the user switches to landscape mode. The ImageView will download an image from the internet and display it. Switching back to portrait, should simply go back to my portrait mode, which has a different set of UI components.

I get a crash when I switch to landscape mode:

because I can't get the id:

chartImageViewLandscape = (ImageView) this.findViewById(R.id.chartImageViewLandscape);

chartImageViewLandscape is in /layout-land/main.xml

How can I get a reference to this?

Sheehan Alam
  • 60,111
  • 124
  • 355
  • 556

4 Answers4

1

What is the question exactly ?

Do you define the android:orientation in both of your layouts ? Beside that, nothing else to do. Android will switch by itself.

If you have different UI components, you probably want to still declare them in both layouts so that any call to findViewById will not crash your app. Just make the layout so that they are not displayed (in a FrameLayout, behind the image for example)

If you prefer to do it more manually, you need to put an android:configChanges="orientation" in your manifest and implement onConfigurationChanged

Matthieu
  • 16,103
  • 10
  • 59
  • 86
  • Sounds good. Also, as far as having it download from the internet on changing the configuration goes, you should definitely find a way to store the image in between orientation changes (for one I've done, I used onRetainNonConfigurationInstance() to save an object and getLastNonConfigurationInstance() to restore the image) so that it doesn't try to redownload the image every time it goes from portrait to landscape and vice versa. – Kevin Coppock Sep 03 '10 at 18:51
  • updated with more details on my problem. @kcoppock can you show me an example of your onRetainNonConfigurationInstance()? – Sheehan Alam Sep 03 '10 at 19:03
1

Sheehan, regarding onRetainNonConfigurationInstance(), below is what I am currently doing for my app in progress. I have the feeling I'm overcomplicating it though, I think there's a simpler way; however, this works just fine for me currently:

So in my activity class "RotationMenu.java":

private Object catcher;
//lots of non-related code here

//directoryList is a returned list of selected directories, that I wish to
//retain in the event of an orientation state change.
String[] directoryList = new String[arrayList.size()];
arrayList.toArray(directoryList);

//here, I set the class Object catcher to the directoryList
catcher = directoryList;

//rest of non-related code

//this method is called when the orientation changes (for me,
//when I open my Droid's hardware keyboard)
public Object onRetainNonConfigurationInstance()
{
    //If I've entered anything into my catcher Object, it will be kept
    //across orientation changes.
    final Object data = catcher;
    return data;
}

Now, in my onCreate(Bundle savedInstanceState) method:

//We retrieve the stored Object and cast it to a String array
final Object recipient = (String[]) getLastNonConfigurationInstance();

//in case the state changes again before the code that sets the directories is run
catcher = recipient;

//if there was any stored data, we can now reinstate the list adapter where the
//directoryList was originally being used.
if(recipient != null)
{
    returnedDirectories.setAdapter(new ArrayAdapter<String>(
        this.getBaseContext(),
        R.layout.simple_list_item_small,
        (String[])recipient));
}

Again, this is how I am doing it currently. If anyone knows of a more efficient method, by all means comment. :)

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • I'll try and implement this into my own code! Do you know how I can pull chartImageViewLandscape from my /layout-land/main.xml? Seems like it is always null! – Sheehan Alam Sep 03 '10 at 22:07
  • You don't want to actually store the View object, from my understanding, that will cause memory leaks. Instead, store the bitmap or drawable that the ImageView contains, and then set that back to the chartImageViewLandscape View in the onCreate() method. – Kevin Coppock Sep 03 '10 at 22:10
  • but I can't even set chartImageViewLandScape because I need to be able to hook it up to the layout via findViewById – Sheehan Alam Sep 03 '10 at 22:11
  • You shouldn't have to. As long as the layout names are the same, it will look it up by its ID, no matter where you move it. Maybe I am misunderstanding? – Kevin Coppock Sep 03 '10 at 22:14
  • /layout-land/main.xml has only an ImageView and nothing else. /layout/main.xml has a listview, and some buttons etc. Hope that clarifies things a bit? – Sheehan Alam Sep 03 '10 at 22:15
  • It does, but both ImageViews should have the same android:id. If so, there should be no issue (except when your code tries to access the id of your listview and buttons when in landscape mode). – Kevin Coppock Sep 03 '10 at 22:20
  • What do you mean by both ImageViews? The ImageView created in code, and the ImageView in my layout? The weird thing is, there are no compile errors, just at runtime chartImageViewLandscape is null. – Sheehan Alam Sep 03 '10 at 22:25
  • The ImageView in your layout will default to whatever value you have defined in the XML. the chartImageViewLandscape is an ImageView object that references that object in your layout. So when you change orientations, onCreate() will be called again, and so the line "chartImageViewLandscape = (ImageView)findViewById(R.id.chartImageViewLandscape)" will be called again, only this time it will find the view from your landscape XML layout. – Kevin Coppock Sep 03 '10 at 22:29
  • Thanks for the extremely detailed answer, and follow thru. I understand fully what is going on, and have implemented your configuration instance code, and it is working as expected. – Sheehan Alam Sep 04 '10 at 00:48
0

Go to your Android "manifest" xml file and make sure the following is present in the "Activity" section:

android:configChanges="orientation|screenSize|keyboardHidden"

Your final "activity" section of the manifest should look similar to the following:

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden"
    android:label="@string/app_name"
    android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>
Purkey
  • 61
  • 7
0

This is from AdMob activity and has more parameters e.g. screenSize is for Android 3.2+

<activity android:name="com.google.ads.AdActivity"
              android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
Svetoslav Marinov
  • 1,498
  • 14
  • 11