Rotation and the Activity Lifecycle

Let’s get back to the bug you found at the end of Chapter 2. Run GeoQuiz, press the NEXT button to reveal the second question, and then rotate the device. (On the emulator, press Command+Right Arrow/Ctrl+Right Arrow or click the rotation icon in the toolbar to rotate.)

After rotating, GeoQuiz will display the first question again. Check Logcat to see what has happened. Your output should look like Figure 3.9.

Figure 3.9  QuizActivity is dead. Long live QuizActivity!

Screenshot shows the activity log for QuizActivity.

When you rotated the device, the instance of QuizActivity that you were looking at was destroyed, and a new one was created. Rotate the device again to witness another round of destruction and rebirth.

This is the source of your bug. Each time you rotate the device, the current QuizActivity instance is completely destroyed. The value that was stored in mCurrentIndex in that instance is wiped from memory. This means that when you rotate, GeoQuiz forgets which question you were looking at. As rotation finishes, Android creates a new instance of QuizActivity from scratch. mCurrentIndex is initialized to 0 in onCreate(Bundle), and the user starts over at the first question.

You will fix this bug in a moment. First, let’s take a closer look at why this happens.

Device configurations and alternative resources

Rotating the device changes the device configuration. The device configuration is a set of characteristics that describe the current state of an individual device. The characteristics that make up the configuration include screen orientation, screen density, screen size, keyboard type, dock mode, language, and more.

Typically, applications provide alternative resources to match device configurations. You saw an example of this when you added multiple arrow icons to your project for different screen densities.

Screen density is a fixed component of the device configuration; it cannot change at runtime. On the other hand, some components, like screen orientation, can change at runtime. (There are other configuration changes that can occur at runtime, such as keyboard availability, language, and multi-window mode.)

When a runtime configuration change occurs, there may be resources that are a better match for the new configuration. So Android destroys the activity, looks for resources that are the best fit for the new configuration, and then rebuilds a new instance of the activity with those resources. To see this in action, let’s create an alternative resource for Android to find and use when the device’s screen orientation changes to landscape.

Creating a landscape layout

In the project tool window, right-click the res directory and select NewAndroid resource directory. You should see a window similar to Figure 3.10 that lists the resource types and qualifiers for those types. Select layout in the Resource type dropdown. Leave the Source set option set to main.

Figure 3.10  Creating a new resource directory

Screenshot shows New Resource Directory window in Android studio.

Next, you will choose how the layout resources will be qualified. Select Orientation in the Available qualifiers list and click the >> button to move Orientation to the Chosen qualifiers section.

Finally, ensure that Landscape is selected in the Screen orientation dropdown, as shown in Figure 3.11. Verify that the Directory name now indicates that your directory is called layout-land. While this window looks fancy, its purpose is just to set the name of your directory. Click OK and Android Studio will create the res/layout-land/ folder.

Figure 3.11  Creating res/layout-land

Screenshot shows New Resolution Directory window in Android Studio.

The -land suffix is another example of a configuration qualifier. Configuration qualifiers on res subdirectories are how Android identifies which resources best match the current device configuration. You can find the list of configuration qualifiers that Android recognizes and the pieces of the device configuration that they refer to at developer.android.com/​guide/​topics/​resources/​providing-resources.xhtml.

When the device is in landscape orientation, Android will find and use resources in the res/layout-land directory. Otherwise, it will stick with the default in res/layout/. However, at the moment there are no resources in the res/layout-land directory. Let’s fix that.

Copy the activity_quiz.xml file from res/layout/ to res/layout-land/. (If you do not see res/layout-land/ in the project tool window, select Project from the dropdown to switch from the Android view. Just be sure to switch back to the Android view when you are done. You can also copy and paste the file outside of Android Studio using your favorite file explorer or terminal app.)

You now have a landscape layout and a default layout. Keep the filename the same. The two layout files must have the same filename so that they can be referenced with the same resource ID.

Now make some changes to the landscape layout so that it is different from the default. Figure 3.12 shows the changes that you are going to make.

Figure 3.12  An alternative landscape layout

Figure shows An alternative landscape layout.

A FrameLayout will replace the top LinearLayout. FrameLayout is the simplest ViewGroup and does not arrange its children in any particular manner. In this layout, child views will be arranged according to their android:layout_gravity attributes.

This means that the TextView, LinearLayout, and Button children of the FrameLayout need android:layout_gravity attributes. The Button children of the LinearLayout will stay exactly the same.

Open layout-land/activity_quiz.xml and make the necessary changes using Figure 3.12. You can use Listing 3.4 to check your work.

Listing 3.4  Tweaking the landscape layout (layout-land/activity_quiz.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/question_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:padding="24dp" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal"
        android:orientation="horizontal" >
      ...
    </LinearLayout>

    <Button
        android:id="@+id/next_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:text="@string/next_button"
        android:drawableRight="@drawable/arrow_right"
        android:drawablePadding="4dp"
        />

</LinearLayout>
</FrameLayout>

Run GeoQuiz again. Rotate the device to landscape to see the new layout (Figure 3.13). Of course, this is not just a new layout – it is a new QuizActivity as well.

Figure 3.13  QuizActivity in landscape orientation

Screenshot shows GeoQuiz screen in a mobile in Landscape mode.

Rotate back to portrait to see the default layout and yet another new QuizActivity.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
44.192.107.255