Android Masterclass: Working with layouts and orientation changes

Dr Rajesh Vasa30 October 2011, 7:23 PM

The one of Android's biggest benefits is that it's found on countless devices of different screen sizes, but it means we have to get familiar with layouts and orientation changes.


In the previous masterclasses we've covered installing the development environment, the organization of an Android project and built a simple interactive application.  In this class, we continue with some additional fundamental concepts -- using layouts to place UI components, and handling device orientation changes.

Android is a very diverse, flexible and open platform. As I write this article, Samsung alone offers devices in 2.8, 3.2, 3.5, 3.7, 4.0, 4.3, 4.5, 5.0, 7.0, 7.7, 8.9, and 10.1inch screens. The other manufacturers have an equally broad range. This diversity is driven by the simple fact that people have different preferences, needs and budgets. Android is also slowly going well beyond the mobile phone/tablet market. It is currentlyused in eBook readers, home automation systems, car entertainment systems (Saab IQon), Televisions (Sony), photo frames, music players, educational tablets, and navigation units. Given the open nature and current trend, Android will likely be a preferred platform to drive the next generation of interface systems in manufacturing, and mobile logistics like the ones used in taxis.

This diversity and flexibility drives adoption in a range of devices and solutions, but it also creates a significant challenge. Developers have to write software that is able to adapt well to different screen sizes, form factors, a range of sensors, and dynamic orientation changes (device rotation). The good new is that the Android platform offers a solid and well-designed framework to deal with the diversity of screen sizes via layouts. However, the heavy lifting of layouts comes at a cost -- the UI is not as fluid/responsive (especially on older/slower phones).  Moreon this shortly, but lets first start by exploring how user interfaces are constructed in general before looking at how developers commonly construct UI for Android applications.

Keeping the tools in shape

Android SDK and the Eclipse IDE tend to release updates to add enhancement and fix defects. It is good practice to keep our tools up to date.

  1. 1. To update Eclipse: Launch the IDE as an Administrator and -- Help menu -> Check for Updates. If there are any updates, install them.
  2. To update Android SDK: From Eclipse IDE, Window -> Android SDK and AVD Manager. Select Installed Packages (in the list on left), Click “Update All…” button and accept all updates that are shown to be available. This will update only the Android packages that you have installed earlier. This process often takes many minutes to complete. If you experience any errors in the update process, check to make sure that you are running the update as an administrator (esp. in Vista and Win7.

Before getting into the details of layout management, here is a quick recap of the core Android concepts covered in the previous master classes.  An Android application is made up of Activities, where an activity maps to an individual window/screen of functionality in an application. We place UI components (called Views) inside a container called a layout (also known as View Group) and attach this layout container to an activity.  The UI is described in an XML file and paired with a Java class that provides the interactivity.  The Android framework mandates conventions, which specify a set of folders that every Android project must have (see Table 1 - Description of Android project folders).  The conventions specify location of resource such as images and data allowing the development tools to process them and generate references to use them from within the XML (UI description) and Java code.  For example, if we place an image in the resource folder (res/drawable-hdpi) the tools generate a reference to the image (a variable of integer type) that we can use within the user interface XML file as well as the Java code.  The conventions also provide an easy method to work with images at multipleresolutions.

Folder

Description

src

Source Code – this is where the Java source code is placed. The Java files are organized into packages that directly map to the folder structure (i.e. the package apc.examples implies a folder structure \apc\examples)

gen

Android tools generate code to refer to resources from the Java and XML code. This generated code is placed in this folder.

Android 2.2

The Android framework library is stored here (generated when we create new project)

assets

Project specific assets are placed here. Developers often store application data files that do not need to change here.

res

This is the location to store resources used in the application. Specifically, images, layouts and strings.

Table 1 - Description of Android project folders

 

UI Layout Approaches

When building user interfaces, there aretwo typical approaches. The first and simplest option is to use absolutepositioning. In this model, we specify the exact (x, y) position of every UIcomponent. For example, place button at position (5,15) and a text field at(25,15).  This method is workable if the screen size is fixed and we areunlikely to change the UI much.  Additionally, if there is any form ofanimation, we have to carefully calculate the different coordinate values. iPhone developers commonly use this approach.

 The second approach involves describing theUI in relative terms using a predefined set of rules. That is, place a label atthe top left of the screen, then followed by a text field next to it and then abutton under the text field.  The description can be relative to the screen, orother UI components.  In this model, we do not have to worry about the screensize (too much) and let the framework deal with the placement of the UIcomponents.  This second approach is relatively flexible, but the framework hasto, (a) calculate if all of the UI components will fit, (b) then compute the(x, y) positions based on the rules ensuring there are no overlappingcomponents, and (c) finally pass that information to a rendering system. Simply put, the flexibility costs a few more CPU cycles.  However, given thepower of the modern CPUs, this whole process is quite fast and we rarely noticethe impact of the multi-pass calculations of the layout framework.  The bestpart is that this approach borrows from the layout algorithms that weredeveloped to render web pages quickly. 

 Interestingly, Android supports bothapproaches for UI Layout: (i) absolute placement, and (ii) relative descriptionof UI components via ‘layouts’. However, given the diversity of Androiddevices, absolute placement is a risky choice and generally not recommended. The use of relative placement based on rules is ideal. Android framework callsthese rule templates ‘layouts’ and we have a number of differentbuilt-in layouts each with certain strengths.

What is a Layout?

The layout is the description of the user interface in an Activity. It specifies the layout hierarchy and structure of the various views (UI components) that the user can see.  A layout is very similar to constructing a HTML page. It is a tree that encapsulates all the views and other nested layouts (see Figure 1).

Macintosh HD:Users:rvasa:Documents:11-APCMag:Tutorial03:images:fig1-layout-hierarchy.pdf

Figure 1 - Layouts encapsulate UI components (views) and can nest other layouts

Android framework allows us to define the layout in two ways:

  • Declare all the UI elements in an XML file
  • Construct the layout on the fly while the application is running via Java code

In this masterclass series, we will stick with XML for describing the layout. XML layout definitions are the most common way in Android as this approach offers a flexible and simple approach that is easy to learn.  This method also respects the software engineering principle ofseparation of concerns – a widely accepted good practice.

Android has many built-in layouts

The Android framework provides us with anumber of built-in default layouts.  All of them inherit the core functionalityfrom a single ancestor called ViewGroup. Most developers refer to these view groups as layouts. The mostcommonly layouts are LinearLayout, TableLayout, and RelativeLayout – all of these inherit from the single ancestor.

All layouts (ViewGroups if we wish to bevery specific) allow us to add Views (UI components), as well as other layoutsinto them.  They also provide a number of convenience features – for instance,to control padding between views and to specify the animation to use when viewsare displayed.  A specific layout, like LinearLayout extends the base functionality by adding rules that define how the views inside it aredisplayed. For example, the Linear Layout offers us the ability to place UIcomponents next to each other either vertically, or horizontally.The TableLayout allows us to add views in a grid – something that is very handy if wewant to display images in a photo album, or the keypad of a calculator. The Relative Layout allows us to add views relative to each other – that is, we canadd a button next to a text view, or under a text view depending on ourpreference.

The high-level description (hopefully) appears to describe a straightforward process. However, layouts are packed witha number of features with some intricacies that take some time to learn. Thereare many ways to construct the UI for an application using layouts.  We can usenested Linear Layouts, or mix in some Relative Layouts with Table Layouts toachieve the same effect.  The only thing to note here is that complex layouts(esp. multiple levels of nesting) will take longer to render since the CPU hasspend more time working out how best to fit the views in the screen.

Layouts and Orientation

Android framework provides flexible layouts, but what happens when the user changes the orientation of the phone (from portrait to landscape)?, or What if they are using a very small screen? When we use layouts (e.g. Linear Layout) to construct a UI, the Android framework will automatically adjust the views on the screen to make optimal use of the real estate.  However, we have an option of providing two different layouts – one for portrait, and one for landscape. We can also provide completely different layouts for smaller screens.  Thankfully, this process is very simple in Android – all we have to do is provide different XML layout descriptions and place it in certain folders.  Once we do this, the Android tools will automatically use the layout depending on the orientation/pixeldensity of the phone.

As discussed in the previous master class,Android conventions mandate a specific folder structure for image resources(e.g. res/drawable-hdpi as the folder where we place high resolution images). Similarly, tosupport layouts for different orientations we place the layout XML files in twodifferent folders. The layout that describes the portrait (default) mode isplaced in res/layout.

p>

The landscape layout description on the other hand is placed in res/layout-land. We use an identical file name in both cases – main.xml (see Figure 2). If we want to support a largerscreen layout like a 7” tablet, we create an appropriate layout XML file andplace that in res/layout-sw600dp.  A complete list of the post-fixes that we need to use for thefolder name is provided online at http://bit.ly/nOUkmF.  So far, we havecovered the background and conceptual aspects – lets get our feet wet with somecode to see how the layouts work in practice.

  

Macintosh HD:Users:rvasa:Desktop:layout-orientation.pdf

Figure 2 - The portrait and landscape layout files have the same name. The folder names are mandated by Android conventions

The About Me Application Revisited

In the previous master class we created anAbout Me application to get started.  We revisit this application, and build abit more complexity in terms of layout and make it handle orientation changes. We will stick with the use of Einstein images, but you are free to use your ownimages. Keep image files under 1 Mb since many older generation Android devicesdo not work with larger resources.

In this revision, we will provide twolayouts for the application: one for portrait orientation, and the other forlandscape.  In the landscape orientation, we will add additional information bymaking use of the table layout.  The functionality will remain unchanged. Rather than build this application from scratch, we will build it on top of theAbout Me application that we constructed in the previous master class.

Steps to download the code, import, and run it as an Eclipse project:

  1. Download AboutMe2.zip – this file contains the Eclipse project.
  2. Open Eclipse IDE, then File -> Import...
  3. General > Existing Projects into Workspace
  4. Select the archive file radio button option
  5. Browse and select the AboutMe2.zip file that you downloaded. This step will open the project
  6. The main activity is now called AboutMeActivity2
  7. Run -> Run (or Ctrl-F11) to launch the application and check it is working properly.

The Trouble with Orientation Changes

When the application is launched it willlike Figure 3 (default portraitorientation).  However, if we flip the orientation using Ctrl-F11in theemulator we get the landscape layout similar to Figure 4.  The application will work(functionally) in both modes with out any further code changes. Unfortunately,the automatic layout applied by the framework in landscape mode (Figure 4) has too much space, and appearsrather sloppy.  As discussed earlier, we can improve the layout by providing adifferent description file (layout xml). However, before getting into that weneed to look at the structure and terminology used in the layout xml file.

Figure 3 - AboutMe2 application in the default portrait mode

 

Figure 4 - AboutMe2 application in landscape mode using the original layout

Understanding the Linear Layout

The most commonly used layout is the LinearLayout.  This is a good layout to start learning the key concepts of the layoutxml. It also provides us with sufficient vocabulary to read the layout filesand make simple changes to it if needed.

The Linear Layout allows us to place view (UI components) consecutively either horizontally or vertically.  If you openthe main.xml file provided as part of the AboutMe2 project, it uses a linearlayout (see code snippet below). The layout declares that we will place theviews one below the other vertically inside this container -- specified by the“vertical” in the orientation attribute of the layout.  We can also use thelinear layout with a “horizontal” orientation which will place the views nextto each other.

http://www.apcmag.com/medroidlinearlayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical" android:layout_width="match_parent"
  android:layout_height="match_parent">

 The TextView which is place inside this linear layout is defined as shown in the code below. The attributes that we need to focus on are the layout height and width.  In this case, the height is provided as wrap_content. This option will cause the view to use much height as needed by the text view and then the rest is wrapped around the other views.  The width on the other hand will match the width of the parent.  All layouts in Android allow this level of control over the height and width attributes.  Furtherdetail about the different layouts is available at http://bit.ly/cxgmzG.

  

<TextView android:textSize="28dp" android:text"=Albert Einstein"
  android:id"@+id/textView1" android:layout_height="wrap_content"
  android:layout_width=match_parent"
<TextView>

Improving the Landscape Layout for AboutMe2

As indicated before, we can improve thelandscape layout by providing a different layout XML file. Rather thanhand-code the layout, the fully developed XML file with one potential landscapelayout is provided for you as part of the resources for this master class.  Toadd this to the project, follow these steps:

  1. In the package explorer view of Eclipse IDE. Right-click on the res folder. Select New -> Folder. Enter the folder name as “layout-land”.
  2. Download main.xml file from to atemporary directory.
  3. Drag and drop the main.xml file into the layout-land folder that youjust created. Eclipse IDE will ask if you want to copy the file – indicate“yes”.
  4. Now double-click on the main.xml file. This will open the landscapelayout description. You can see the graphical view (option is in bottom left hand of the main.xml file tab).
  5. If you want to see the portrait view. In the graphical layoutwindow, the top bar has a drop-down lists that allow you to adjust the screen size and select the portrait/landscape view.  Eclipse will automatically switch to the correct layout file to use. You can also use the screen size drop-down list to see how the layout will appear on a smaller screen.
  6. Once you have the landscape and portrait modes tested in the Eclipse IDE graphical editor, run the application in the emulator and test by changing orientation from landscape to portrait (Ctrl-F11 switches the emulator orientation).
The key changes to the layout (compared to the default) are: (i) using a horizontal orientation for the linear layout that contains the UI, and (ii) create a new relative layout to place the text/buttoninto it (see code snippet below). Figure 5 shows how the application will lookwith the improvements along with an annotation of the layouts in use.

 The use of relative layout in the landscapeorientation allows us to place the views inside it with greater precision sincewe specify layout relative to other views. We can indicate that we want thebutton to be in the bottom right, while the text is on the top right (see thecode listing below, or browse the code directly in Eclipse).  We also use thegravity for the text to specify right alignment. The gravity ensures that textwill stick to the right margin on smaller screens.  See http://bit.ly/cxsMd3 for more information about the use of relative layout.

  

<RelativeLayout android:id="@+id/RelativeLayout1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:padding="5dp" android:orientation="vertical">
 
<Button android:id="@+id/aboutMeButton"android:layout_height="wrap_content"
android:onClick="showAboutMessage" android:layout_width="wrap_content"
android:text="About Me"android:layout_alignParentBottom>="true"
android:layout_alignParentRight="true"></Button>
 
<TextViewandroid:textSize="28dp"android:layout_height="wrap_content"
android:id="@+id/textView1" android:layout_width="wrap_content"
android:gravity="right" android:text="Albert Einstein"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"></TextView>
</RelativeLayout>
 

Figure 5 - Explanation of the nested layouts used to improve landscape orientation

Using it for real

The code blocks that we have been working on so far were quite simple. However, it still allows us to build an application that allows us to get a presence on the market place (if we wish). Here is a slightly more realistic example that shows how we can use the concepts covered so far to build an app. to get the word out about an upcoming game.

Pub Games isan exciting Aussie start-up building games for mobile (iOS and Android). In this example, we will use only the concepts covered so far to build an app that they could put on the Android market place to generate some buzz about their upcoming game – it even shows a screen shot andprovides some information about the company (see Figure 6).

You can use the code as a template to get an app. that will help you publish some details about your own company, or make a mobile personal card.  The code is available for download here.

This sample application uses nested linear layouts with images and text views. We do not add Java code to the block generated automatically by the tools.  The links and email address in the application are clickable (TextView’s provide an autoLink attribute that we can use to provide the type of link). When these links are clicked, the device will open a web browser, or the email client.  Have a go and change the images / text / links to suit your needs. In the next master class we will go continue to add more depth to the application.

Figure 6 - Sample application for Pub Games

Deploying Application to your Android Phone

If you have an Android phone and it is running Android 2.2 (or higher) then you can deploy the application directly from Eclipse IDE to your phone:

1. Set your phone to development mode by going to Settings -> Applications -> Development and Enable USB Debugging. 

2. Connect your device to the computer and Eclipse will show your phone as a potential target when you attempt to run the application (Run menu -> Run). Select this option and run. Eclipse IDE will sign the application; deploy to the phone, and then launch it.

3. The application will be installed on the phone and will work even after you disconnect the phone from the computer.

4. Disable USB debugging on the phone once you are done in Settings > Applications > Development.

 

Java Language – Key Building Blocks

Java is an object-oriented language that is used heavily in the Android framework. Although Android is bi-lingual and supports C++, most of the development is done in Java. It is widely used in enterprise applications (typically, data driven software and messaging systems). Google selected Java as the key language mainly to ensure access to a large pool of Java developers. This is also greatly assisted by the fact that most universities in the world still teach Java in their courses. The core Java language is quite small and remarkably similar to other object-oriented languages. The challenging aspect of Java, and most other modern languages is learning the frameworks, design patterns and the standard libraries. For example, there are 65 different functions available for string manipulation in Java. Learning these intricacies is the real challenge, but this is the knowledge that gives us the productivity when building software system.

In order to build software for Android, one needs a reasonable skill in Java. In this master class, and over the next few ones we will go over the key concepts in Java to cover the essential aspects of the language and help you read the code. 

Java programs are made up of classes that contain methods and fields. The classes are encapsulated in a package. Here is a simple Java class – with the comments providing a description of the class:

package apc.examples;
import java.util.Date;
 
public class Customer
{
  /** The following are two fields that
  * store information about a customer */
  privateString name;
  private Date dob;
   
  /** This is a constructor */
  public Customer(String n, Date d)
  {
 
  name = n;
  dob = d;
  }
  /** This method returns the name of the customer when called */
  public String getName()
  {
  return name;
   
  /** This method returns a string showing name and DOB */
  Public String toString()
  {
  String msg = name+" was born on "+dob;
  return msg;
  }
}
 

The above class is defined as part of the apc.examples package. We use a package name to group related classes in Java. In this instance, the class has two fields to store the information about a customer (name and dob). Classes in object-oriented languages need a constructor to help initialize the fields – and we have one constructor in our code above. In this sample code, we have two methods. The first one returns the name of the customer. The second one returns a string representation of the customer. In the second method (toString), we construct the string by using the concat (+) operator. In this class, we also used an import statement (see second line of code) to indicate that we need the Date class to store the date of birth (in the dob field). In Java, the import statements are used heavily to refer to classes that are defined outside of the package that a class belongs to. The standard library has thousands of classes like the Date -- we can use the functionality from any of these by importing them into our code.

Once we define out class, we can create and use objects of this class type. See the code below to see how we can construct and use an object of Customer class type.

Date dob1 = new GregorianCalendar(1960, 1, 12).getTime();
Customer cust1 = new Customer("PP", dob1);
System.out.println(cust1.getName());

We use a Gregorian calendar for precision to create the date of birth information. Once that is done, we construct a new Customer object (cust1), and then print out the name of the customer by referring to that object. The print routine is part of the System.out class, which is provided by the Java standard library. We will look at further aspects of Java in the next Master class. If you want to learn the language in greater depth the online course by Oracle is excellent -- at http://bit.ly/dSYtNN.

PREVIOUS: Building a simple Android app | NEXT: Working with Multiple Activities

Post your comment



anonymous user Anonymous user

APC May 2013

May 
APC
out now!

Tags