Screen Rotation

Background

One of the more frustrating things about creating Android layouts is being able to gracefully handle screen rotation.  By default, there is only one layout folder created for you, called layout.  Unless you specify otherwise, the layout that you assign in the app's onCreate() method (e.g. setContentView(R.layout.main)), will apply in both screen orientations.  However, most apps use a different layout based on the screen orientation.  

Implementation

There are a couple of ways to accomplish this:  

  1. Programatically:  
    1. write the appropriate event handler code in your Java file such that when the app detects a screen rotation, it sets a new layout: 
      @Override
      public void onConfigurationChanged(Configuration newConfig) {
      	super.onConfigurationChanged(newConfig);
      	// Checks the orientation of the screen
      	if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
      	      setContentView(R.layout.landscapeLayoutFile);
      	} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
      	      setContentView(R.layout.portraitLayoutFile);
      	}
      }
    2. In addition to the Java code, you must also add the following attribute to the respective Activity entry in the application's manifest file.  This will allow your app to capture the orientation change event: 
      android:configChanges="keyboardHidden|orientation"

       

  2. XML: Create a new layout folder in the res folder called layout-land.  Put the landscape layout in this folder, and ensure that it has the exact same name as the portrait version.  When the device's screen orientation changes, the proper layout file will automatically be chosen and applied by the OS.

Generally speaking, both options give the same end result.  However, option 2 is more succinct, and it allows the SDK to do a lot of the work for us....so we'll use option 2.  

IMPORTANT - All corresponding Views must have the same id. This allows the Activity to reference the proper View when the layout file is swapped following an orientation change.  When implementing method 2, both layout file names must be EXACTLY THE SAME. 
 

Detecting Screen Orientation

At this point, you've probably made the mental note that there may be Views in your landscape layout that do not exist in the portrait version (for example, in Assignment 1, the landscape calulator interface has many nore buttons).  Why does this matter? Let’s say for example that in your onCreate() method, you put in all the code to create references to every button, including those that are exclusive to the landscape View. You start up your app to test it and it crashes. Why?

Well, when your app starts, it will initially load the portrait layout (assuming the device is in portrait mode to start):

setContentView(R.layout.portraitLayoutFile);

Since the portrait layout file does not contain some of the Views you’ve created references to in onCreate(), it will fail to find them…and the app will crash miserably.

How can you prevent this? There are a few solutions, but I’ll give you two. Both solutions take into account our main problem: that some of the buttons in our app only exist in the landscape layout file. So it makes sense that you only reference the landscape-only buttons when in landscape mode: