The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Large-Screen Strategies and Tactics

So far, we have been generally ignoring screen size. With the vast majority of Android devices being in a fairly narrow range of sizes (3” to just under 5”), ignoring size while learning is not a bad approach. However, when it comes time to create a production app, you are going to want to strongly consider how you are going to handle other sizes, mostly larger ones (e.g., tablets).

Objective: Maximum Gain, Minimum Pain

What you want is to be able to provide a high-quality user experience without breaking your development budget — time and money — in the process.

An app designed around a phone, by default, may look fairly lousy on a tablet. That is because Android is simply going to try to stretch your layouts and such to fill the available space. While that will work, technically, the results may be unpleasant, or at least ineffective. If we have the additional room, it would be nice to allow the user to do something with that room.

At the same time, though, you do not have an infinite amount of time to be dealing with all of this. After all, there are a variety of tablet sizes. While ~7” and ~10” screens are the most common, there are certainly others that are reasonably popular (e.g., Amazon’s Kindle Fire HD 8.9”).

The Fragment Strategy

Some apps will use the additional space of a large screen directly. For example, a painting app would use that space mostly to provide a larger drawing canvas upon which the user can attempt to become the next Rembrandt, Picasso, or Pollock. The app might elect to make more tools available directly on the screen as well, versus requiring some sort of pop-up to appear to allow the user to change brush styles, choose a different color, and so forth.

However, this can be a lot of work.

Some apps can make a simplifying assumption: the tablet UI is really a bunch of phone-sized layouts, stitched together. For example, if you take a 10” tablet in landscape, it is about the same size as two or three phones side-by-side. Hence, one could imagine taking the smarts out of a few activities and having them be adjacent to one another on a tablet, versus having to be visible only one at a time as they are on phones.

For example, consider the original edition of the Gmail app for Android.

On a phone, you would see conversations in a particular label on one screen:

Gmail, On a Galaxy Nexus, Showing Conversations
Figure 326: Gmail, On a Galaxy Nexus, Showing Conversations

… and the list of labels on another screen:

Gmail, On a Galaxy Nexus, Showing Labels
Figure 327: Gmail, On a Galaxy Nexus, Showing Labels

… and the list of messages in some selected conversation in a third screen:

Gmail, On a Galaxy Nexus, Showing Messages
Figure 328: Gmail, On a Galaxy Nexus, Showing Messages

Whereas on a 7” tablet, you would see the list of labels and the conversations in a selected label at the same time:

Gmail, On a Galaxy Tab 2, Showing Labels and Conversations
Figure 329: Gmail, On a Galaxy Tab 2, Showing Labels and Conversations

On that 7” tablet, tapping on a specific conversation brings up the list of messages for that conversation in a new screen. But, on a 10” tablet, tapping on a specific conversation showed that conversation, plus the list of conversations, side-by-side:

Gmail, On a Motorola XOOM, Showing Conversations and Messages
Figure 330: Gmail, On a Motorola XOOM, Showing Conversations and Messages

Yet all of that was done with one app with very little redundant logic, by means of fragments.

The list-of-labels, list-of-conversations, and list-of-messages bits of the UI were implemented as fragments. On a smaller screen (e.g., a phone), each one is displayed by an individual activity. Yet, on a larger screen (e.g., a tablet), more than one fragment is displayed by a single activity. In fact — though it will not be apparent from the static screenshots — on the 10” tablet, the activity showed all three fragments, using animated effects to slide the list of labels off-screen and the list of conversations over to the left slot when the user taps on a conversation to show the messages.

The vision, therefore, is to organize your UI into fragments, then choose which fragments to show in which circumstances based on available screen space:

Tablets vs. Handsets (image courtesy of Android Open Source Project)
Figure 331: Tablets vs. Handsets (image courtesy of Android Open Source Project)

Changing Layout

One solution is to say that you have the same fragments for all devices and all configurations, but that the sizing and positioning of those fragments varies. This is accomplished by using different layouts for the activity, ones that provide the sizing and positioning rules for the fragments.

So far, most of our fragment examples have been focused on activities with a single fragment, like you might use on smaller screens (e.g., phones). However, activities can most certainly have more than one fragment, though you will need to provide the “slots” into which to plug those fragments.

For example, you could have the following in res/layout-w720dp/main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <FrameLayout
    android:id="@+id/countries"
    android:layout_weight="30"
    android:layout_width="0px"
    android:layout_height="match_parent"
  />
  <FrameLayout
    android:id="@+id/details"
    android:layout_weight="70"
    android:layout_width="0px"
    android:layout_height="match_parent"
  />
</LinearLayout>

Here we have a horizontal LinearLayout holding a pair of FrameLayout containers. Each of those FrameLayout containers will be a slot to load in a fragment, using code like:


getSupportFragmentManager().beginTransaction()
                                 .add(R.id.countries, someFragmentHere)
                                 .commit();

In principle, you could also have a res/layout-h720dp/main.xml that holds both of the same FrameLayout containers, but just in a vertical LinearLayout:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <FrameLayout
    android:id="@+id/countries"
    android:layout_weight="30"
    android:layout_height="0dp"
    android:layout_width="match_parent"
  />
  <FrameLayout
    android:id="@+id/details"
    android:layout_weight="70"
    android:layout_height="0dp"
    android:layout_width="match_parent"
  />
</LinearLayout>

As the user rotates the device, the fragments will go in their appropriate slots.

Changing Fragment Mix

However, for larger changes in screen size, you will probably need to have larger changes in your fragments. The most common pattern is to have fewer fragments on-screen for an activity on a smaller-screen device (e.g., one fragment at a time on a phone) and more fragments on-screen for an activity on a larger-screen device (e.g., two fragments at a time on a tablet).

So, for example, as the counterpart to the res/layout-w720dp/main.xml shown in the previous section, you might have a res/layout/main.xml that looks like this:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/countries"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
/>

This provides a single slot, R.id.countries, for a fragment, one that fills the screen. For a larger-screen device, held in landscape, you would use the two-fragment layout; for anything else (e.g., tablet in portrait, or phone in any orientation), you would use the one-fragment layout.

Of course, the content that belongs in the second fragment would have to show up somewhere.

Sometimes, when you add another fragment for a large screen, you only want it to be there some of the time. For example, a digital book reader (like the one we are building in the tutorials) might normally take up the full screen with the reading fragment, but might display a sidebar fragment based upon an action bar item click or the like. If you would like the BACK button to reverse your FragmentTransaction that added the second fragment — so pressing BACK removes that fragment and returns you to the single-fragment setup — you can add addToBackStack() as part of your FragmentTransaction construction:


getSupportFragmentManager().beginTransaction()
                           .addToBackStack(null)
                           .replace(R.id.sidebar, f)
                           .commit();

We will see this in the next tutorial.

The Role of the Activity

So, what is the activity doing?

First, the activity is the one loading the overall layout, the one indicating which fragments should be loaded (e.g., the samples shown above). The activity is responsible for populating those “slots” with the appropriate fragments. It can determine which fragments to create based on which slots exist, so it would only try to create a fragment to go in R.id.details if there actually is an R.id.details slot to use.

Next, the activity is responsible for handling any events that are triggered by UI work in a fragment (e.g., user clicking on a ListView item), whose results should impact other fragments (e.g., displaying details of the clicked-upon ListView item). The activity knows which fragments exist at the present time. So, the activity can either call some method on the second fragment if it exists, or it can call startActivity() to pass control to another activity that will be responsible for the second fragment if it does not exist in the current activity.

Finally, the activity is generally responsible for any model data that spans multiple fragments. Whether that model data is held in a “model fragment” (as outlined in the chapter on fragments) or somewhere else is up to you.

Fragment Example: The List-and-Detail Pattern

The preview of this section is off trying to sweet-talk the Khaleesi into providing us with a dragon.

Other Master-Detail Strategies

The preview of this section was lost in the sofa cushions.

Showing More Pages

The preview of this section was abducted by space aliens.

Fragment FAQs

The preview of this section left for Hollywood to appear in a reality TV show.

Screen Size and Density Tactics

The preview of this section was whisked away by a shark-infested tornado.

Other Considerations

The preview of this section was traded for a bag of magic beans.