IS 389 ANDROID FRAGMENT LAB

EKEDAHL

ABSTRACT

In this lab, you will work with Android Fragments. The application that you create for this lab will show you the event lifecycle of adding and replacing fragments and how fragments are displayed within their container (activity)

  • For this lab, I have posted this document electronically. I suggest that you load the Microsoft Word document. That way you can copy and paste my code into your lab.
  • There is a significant amount of layout and Java code in this program. Thus, the program assumes that you are starting with the project IS389FragmentLayoutLab.zip. (available on the Fragments page of my Web site). A summary of this code appears in the Work Completed section:

KEY TERMS

  • Back stack: As users navigate from activity to activity or from fragment to fragment, activities and fragments are added and replaced from what is called the back stack.
  • Fragment: a portion of a user interface within and activity. Fragments are used to build multi-pane user interface.
  • Task: When you run an application, that application is considered a task. The same task is used as you navigate from activity to activity and to and from activities outside of your application.

Work Completed

Because there is so much code in this lab, I have completed the boiler plate for you. That is, I have created all of the files that comprise the application. You will review these files and their purpose before starting to write the code that will “connect the dots” together.

HANDS-ON STEPS: Importing the template project into Eclipse

In the following sequence of steps, you will import the startup activity into Eclipse and review its contents.

  1. From by Web site, download the file IS389FragmentLayoutLab.zip and import it into Eclipse. This file appears on the Fragments page.

The following excerpt from the Package Explorer shows the files and their folder location. Some of these files have been completes. Some contain only a template for the code that you will write. Finally, some of the code derives from the code you wrote in the networking and ListView labs.

The res/layout/strings.xml file contains all of the prompt resources and activity titles as usual:

In this application, the main activity operates similar to the main activity for the other applications that you have written. The main activity contains buttons used to display the other activities in the application. There are two activity_main.xml layout files and one MainActivity.java file.

  • The first layout is named activity_main.xml and appears in the layout folder. This layout will be rendered while the device is in portrait mode. The activity contains two buttons and two fragments that are rendered vertically. (android:orientation="vertical")
  • The second layout is named activity_main.xml and appears in the layout-land folder. This layout will be rendered while the device is in landscape mode. The activity contains two buttons and two fragments that will be renderedhorizontally.(android:orientation="horizontal")

Both of the above layout files have the same widgets having the same name values for the (+@id/) property. Both layout files share the same Java code. The only difference between the two is the orientation / position of the widgets. Both layout files contain the following buttons:

Button

android:id="@+id/btnConfig"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/prompt_button_config"/>

Button

android:id="@+id/btnFragmentList"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/prompt_button_fragmentList"/>

The src/MainActivity.java file contains the Java code to for the two activity_main.xml files. The code file is shared between the two activity files that will render the page in portrait and landscape modes. I have written log messages in each of the event handlers (listeners) so that you can see the event lifecycle for the activities and fragments:

The MainActivity.java file displays two other activities.

  • The activity named ActivityConfig.java contains code to get configuration and display information discussed in class.
  • The activity named ListActivityFragment.java contains the activity that will render one or two fragments based on the orientation.
  • A third activity named DetailActivityFragment.java will render the detail fragment for the while the device is in portrait monde.

The ActivityConfig.java files used two layout files that are part of the startup package. Again, both layouts have the same widgets having the same names. In portrait mode, the widgets are rendered vertically. In landscape mode, the prompts and corresponding values are rendered horizontally using nested linear layouts.

The following code shows the layout /config_activity.xml layout file. It has<TextView> prompts and values stored in <EditText> widgets rendered one below another. The orientation of the <LinearLayout> is vertical.

LinearLayoutxmlns:android="

xmlns:tools="

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

android:orientation="vertical"

tools:context="com.example.fragmentorientation.ConfigActivity"

TextView

android:id="@+id/tv_title"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="PORT"/>

TextView

android:id="@+id/tv_density_dpi"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_density_dpi_prompt"/>

EditText

android:id="@+id/edit_density_dpi"

android:labelFor="@id/tv_density_dpi"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:editable="false"

android:ems="10"

</EditText

TextView

android:id="@+id/tv_width_pixels"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_width_pixels_prompt"/>

EditText

android:id="@+id/edit_width_pixels"

android:labelFor="@id/tv_width_pixels"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:editable="false"

android:ems="10"

</EditText

TextView

android:id="@+id/tv_height_pixels"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_height_pixels_prompt"/>

EditText

android:id="@+id/edit_height_pixels"

android:labelFor="@id/tv_height_pixels"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:editable="false"

android:ems="10"

</EditText

TextView

android:id="@+id/tv_orientation"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text=""/>

TextView

android:id="@+id/tv_screen_height_dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_screen_height_dp_prompt"/>

EditText

android:id="@+id/edit_screen_height_dp"

android:labelFor="@id/tv_height_pixels"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:editable="false"

android:ems="10"

</EditText

TextView

android:id="@+id/tv_screen_width_dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_screen_width_dp_prompt"/>

EditText

android:id="@+id/edit_screen_width_dp"

android:labelFor="@id/tv_height_pixels"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:editable="false"

android:ems="10"

</EditText

</LinearLayout

The following code segment shows the layout-land/config_activity.xml layout file. Again, this layout will be rendered while the device is in landscape mode. It is a bit more complex:

  • The first child of the <LinearLayout> widget is a <ScrollView> widget. The <ScrollView>. The ScrollView> widget makes its child scrollable. A <ScrollView> must have one child layout which is the layout that becomes scrollable. You should never use a <ScrollView> with a <ListView> because the <ListView> is already scrollable.
  • Pairs of prompts and values are laid out horizontally by enclosing them in another child <LinearLayout>.

<?xmlversion="1.0"encoding="utf-8"?>

LinearLayoutxmlns:android="

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:scrollbars="vertical"

ScrollView

android:layout_width="fill_parent"

android:layout_height="fill_parent"

LinearLayout

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical"

TextView

android:id="@+id/tv_title"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:editable="false"

android:text="LAND"/>

LinearLayout

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal"

TextView

android:id="@+id/tv_density_dpi"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_density_dpi_prompt"

android:labelFor="@id/edit_density_dpi"/>

EditText

android:id="@+id/edit_density_dpi"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:ems="10"

android:editable="false"

</EditText

</LinearLayout

LinearLayout

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal"

TextView

android:id="@+id/tv_width_pixels"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_width_pixels_prompt"/>

EditText

android:id="@+id/edit_width_pixels"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:ems="10"

android:editable="false"

android:labelFor="@id/tv_width_pixels"

</EditText

</LinearLayout

LinearLayout

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal"

TextView

android:id="@+id/tv_height_pixels"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_height_pixels_prompt"/>

EditText

android:id="@+id/edit_height_pixels"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:ems="10"

android:editable="false"

android:labelFor="@id/tv_height_pixels"

</EditText

</LinearLayout

TextView

android:id="@+id/tv_orientation"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text=""/>

LinearLayout

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal"

TextView

android:id="@+id/tv_screen_height_dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_screen_height_dp_prompt"/>

EditText

android:id="@+id/edit_screen_height_dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:ems="10"

android:editable="false"

android:labelFor="@id/tv_height_pixels"

</EditText

</LinearLayout

LinearLayout

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal"

TextView

android:id="@+id/tv_screen_width_dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/tv_screen_width_dp_prompt"/>

EditText

android:id="@+id/edit_screen_width_dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:ems="10"

android:editable="false"

android:labelFor="@id/tv_height_pixels"

</EditText

</LinearLayout

</LinearLayout

</ScrollView

</LinearLayout

There are two activity layouts designed to render fragments. The layout named activity_frgment_list.xml in the layout and layout-land folders. One will render a single fragment containing a <ListView> the second twill render two fragments. The first contains the same <ListView>. The second is designed to render detail information. The template for the two fragments have already been created. In this lab, you will create the complete code for the two layouts. The fragments will appear in the following files:

  • The fragment layout named list_fragment.xml is the fragment that will render a bound <ListView> The binding process is the same as you discovered in previous labs.
  • The fragment named detail_fragment.xml will render the detail information corresponding to the selected item in the list fragment.

There are two layout files used to render the <ListView>. These layouts are exactly the same as the <ListView> layouts discussed in previous labs.

  • The layout named lv_header_row.xmlis used to render the header row in in the <ListView>.
  • The layout named lv_item_row.xml renders the detail rows in the <ListView>.

Finally, the following files contain the code containing the Weather class and WeatherAdapter, which is derivedf

  • The file named src/Weather.javacontains the same Weather class discussed in previous labs.
  • The file name src/WeatherAdapter.java contains the same WeatherAdapter class discussed in previous labs with a couple of slight modifications.

Working with Device Orientation

Up to this point, your programs have been implemented such that they expect the device to be in portrait orientation. However, well-behaved applications should behave well in both portrait and landscape orientations. In this section of the lab, you will learn how to determine the current device position, and information about the current screen size.

The android.content.res.Resources class is used to access an application’s resources. This class has several public methods used to access specific resource categories. The getResources()method of the Context class gets a reference to the application’s current resources. The Resources class, in turn supports, methods get the display metrics and device configuration:

  • The getDisplayMetrics() class gets the current DisplayMetrics instance. It has properties named widthPixles and heightPixels to get the absolute height and width of the device. The densityDpi property gets the dots per inch. There are several other properties and methods used to get additional device information.
  • The getConfiguration() method gets the current configuration information. This configuration information includes the device orientation and screen resolution information. It describes information about the keyboard and touch screen too. The data returned by getConfiguration() is of type android.content.res.Configuration.

The Configuration class, in turn, supports the following properties.

  • The screenHeightDp gets the current screen height (in device independent units). This is the height of the screen based on the current orientation. The screenWidthDp gets the current screen width (in device independent units). This is the width of the screen based on the current orientation. The orientation property gets the device orientation. The value can be one of the following constants. ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT, and ORIENTATION_UNDEFINED.

The following code segment shows how to get the display metrics

DisplayMetrics metrics = getResources().getDisplayMetrics();

intwidthPixels = metrics.widthPixels;

intheightPixels = metrics.heightPixels;

intdensityDpi = metrics.densityDpi;

The statement fragment getResources().getDisplayMetrics() gets the display metrics applicable to the current context’s resources.The remaining statements read the respective properties and store the values in corresponding variables.

The following code segment shows how to get the configuration information:

Configuration config = getResources().getConfiguration();

switch (config.orientation)

{

case Configuration.ORIENTATION_LANDSCAPE:

{

tv_orientation.setText("ORIENTATION_LANDSCAPE");

break;

}

case Configuration.ORIENTATION_PORTRAIT:

{

tv_orientation.setText("ORIENTATION_PORTRAIT");

break;

}

case Configuration.ORIENTATION_UNDEFINED:

{

tv_orientation.setText("ORIENTATION_UNDEFINED");

break;

}

}

int screenHeightDp = config.screenHeightDp;

int screenWidthDp = config.screenWidthDp;

The statement fragment getResources().getConfiguration() gets the current configuration instance applicable to the current resources. The switch statement displays a message based on the current orientation (config.orientation). The final statements get the screen height and width and store the result in int variables.

HANDS-ON STEPS: Determining the device orientation and screen resolution[ME1].

In the following steps, you will add the code the ConfigActivity.java file to get information from the Resources and Configuration classes and display the results in the form’s widgets. Again, much of the code for this activity has already been created for you.

The widgets have been created for both the portrait and landscape layouts. The src/configActivity.java file has been created from a template. You will create two procedures to display information from the DisplayMetrics and Configuration classes.

  1. Activate the Code Editor for the src/ConfigActivity.java file. At the end of the ConfigActivity class, create the following procedure named ShowDisplayMetrics().

protectedvoid ShowDisplayMetrics()

{

EditText edit_density_dpi = (EditText) findViewById(R.id.edit_density_dpi);

EditText edit_width_pixels = (EditText) findViewById(R.id.edit_width_pixels);

EditText edit_height_pixels = (EditText) findViewById(R.id.edit_height_pixels);

DisplayMetrics metrics = getResources().getDisplayMetrics();

intwidthPixels = metrics.widthPixels;

edit_width_pixels.setText(Integer.toString(widthPixels));

intheightPixels = metrics.heightPixels;

edit_height_pixels.setText(Integer.toString(heightPixels));

intdensityDpi = metrics.densityDpi;

edit_density_dpi.setText(Integer.toString(densityDpi));

}

  1. Create another procedure named ShowConfiguration() and enter the following code:

protectedvoid ShowConfiguration()

{

TextView tv_orientation = (TextView)

findViewById(R.id.tv_orientation);

EditText edit_screen_height_dp = (EditText)

findViewById(R.id.edit_screen_height_dp);

EditText edit_screen_width_dp = (EditText)

findViewById(R.id.edit_screen_width_dp);

Configuration config = getResources().getConfiguration();

switch (config.orientation)

{

case Configuration.ORIENTATION_LANDSCAPE:

{

tv_orientation.setText("ORIENTATION_LANDSCAPE");

break;

}

case Configuration.ORIENTATION_PORTRAIT:

{

tv_orientation.setText("ORIENTATION_PORTRAIT");

break;

}

case Configuration.ORIENTATION_UNDEFINED:

{

tv_orientation.setText("ORIENTATION_UNDEFINED");

break;

}

}

intscreenHeightDp = config.screenHeightDp;

intscreenWidthDp = config.screenWidthDp;

edit_screen_height_dp.setText(Integer.toString(screenHeightDp));

edit_screen_width_dp.setText(Integer.toString(screenWidthDp));

}

  1. Write the following statements in the onCreate() method to call these procedures.

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_config);

ShowDisplayMetrics();

ShowConfiguration();

}

  1. Test the application. Click the Config button display the configuration activity. The configuration information should be read and displayed in the activity’s widgets. Rotate the device to appear in portrait mode. Using the emulator, rotate the device by clicking LEFT-CTRL F11.
    Note that the portrait activity is rendered and the widgets appear horizontally.

Creating Multiple Layouts

The imported project contains two layouts for the main activity (activity_main.xml) and two layouts for the configuration activity (activity_config.xml). While very simple it does illustrate how activities are rendered and destroyed automatically by the Android system.

HANDS-ON STEPS: Understanding multiple layouts and

In the following sequence of steps, you will setup the application’s activities and develop the code to determine the application’s orientation.

For this application, you will use several layouts, some of which have been created for you. Some of these layouts will render an activity in portrait mode depending on the orientation of the device. Others will be used to layout activity fragments.

The following list describes the activities and layouts[ME2]

Working with Fragments

When working with fragments, an activity contains widgets that act as templates. Each template, in turn, renders a fragment. In this example, you will use the <FrameLayout> widget as the template. Note the following about the <FrameLayout> class:

  • The purpose of the <FrameLayout> class is to block out an area of the screen to display a single item. In this example, you will use the <FrameLayout> to display a fragment made up of a single <LinearLayout>.
  • The FrameLayoutis derived from the ViewGroup class. The FrameLayout has constants that define how to the widget appears in its container.

While there are many reasons to create fragments, you will use them here to display master data in portrait mode, and both master and detail data in landscape mode. This implementation requires:

  • An activity namedres\layout\activity_fragment_list.xml that will render only the List fragment. A <FrameLayout> widget will be used as the placeholder that will render the list fragment (list_fragment.xml).
  • An activity named res\layout-land\ activity_fragment_list.xml that will render both the List and Detail fragment (list_fragment.xml and detail_fragment.xml).

Each fragment has a layout and may have both portrait and landscape layouts. These layouts are no different than the layouts with which you have been working. In this example, you will complete two layouts for the two fragments. The fragments themselves do not have landscape layouts as they will appear the same shape and size regardless of the device’s orientation.

  • The first fragment layout named list_fragment.xml contains one <TextView>used to display a title and a <ListView> to display a list. The list implementation is the same as the list implementation used in previous labs.
  • The second fragment named detail_fragment.xml contains the widgets that will render detail data for the selected weather day.

In the following sequence of steps, you will create the layout code for the two fragments, While the fragments have been created, the following steps will create an XML layout file. In the Package Explorer, open the res/layout folder. Right-click the folder name. Select New Android XML file to create the layout file.