In this chapter, you will add a second activity to GeoQuiz. An activity controls a screen of information, and this activity will add a second screen that offers users a chance to cheat on the current question by showing the answer. Figure 5.1 shows the new activity.
Figure 5.1 CheatActivity
offers the chance to peek at the answer
If users choose to view the answer and then return to the QuizActivity and answer the question, they will get a new message, shown in Figure 5.2.
Why is this a good Android programming exercise? Because you will learn how to:
Create a new activity and a new layout for it.
Start an activity from another activity. Starting an activity means asking the OS to create an activity instance and call its onCreate(Bundle) method.
Pass data between the parent (starting) activity and the child (started) activity.
There is a lot to do in this chapter. Fortunately, some of the grunt work can be done for you by Android Studio’s New Activity wizard.
Before you invoke the magic, open strings.xml and add all the strings you will need for this chapter.
Listing 5.1 Adding strings (strings.xml
)
<resources> ... <string name="incorrect_toast">Incorrect!</string> <string name="warning_text">Are you sure you want to do this?</string> <string name="show_answer_button">Show Answer</string> <string name="cheat_button">Cheat!</string> <string name="judgment_toast">Cheating is wrong.</string> </resources>
Creating an activity typically involves touching at least three files: the Java class file, an XML layout, and the application manifest. If you touch those files in the wrong ways, Android can get mad. To ensure that you do it right, you can use Android Studio’s New Activity wizard.
Launch the New Activity wizard by right-clicking on your com.bignerdranch.android.geoquiz package in the project tool window. Choose New → Activity → Empty Activity, as shown in Figure 5.3.
You should then see a dialog like Figure 5.4. Set Activity Name to CheatActivity. This is the name of your Activity subclass. Layout Name will be automatically set to activity_cheat. This will be the base name of the layout file the wizard creates.
The defaults for the remaining fields are fine, but take care to ensure that the package name is what you expect. This determines where CheatActivity.java will live on the filesystem. Click the Finish button to make the magic happen.
Now it is time to make the UI look good. The screenshot at the beginning of the chapter shows you what CheatActivity’s view should look like. Figure 5.5 shows the widget definitions.
Open activity_cheat.xml from the layout directory and switch to the Text view.
Try creating the XML for the layout using Figure 5.5 as a guide. Replace the sample layout with a new LinearLayout and so on down the tree. After Chapter 9, we will only show layout diagrams like Figure 5.5 instead of long passages of XML, so it is a good idea to start using them now to create your layout XML. You can check your work against Listing 5.2.
Listing 5.2 Filling out the second activity’s layout (activity_cheat.xml
)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" tools:context="com.bignerdranch.android.geoquiz.CheatActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="24dp" android:text="@string/warning_text"/> <TextView android:id="@+id/answer_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="24dp" tools:text="Answer"/> <Button android:id="@+id/show_answer_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/show_answer_button"/> </LinearLayout>
Notice the special XML namespace for tools
and the tools:text
attribute on the
TextView widget where the answer will appear.
This namespace allows you to override any attribute on a widget for the purpose of
displaying it differently in the Android Studio preview.
Because TextView has a text
attribute, you can provide a literal
dummy value for it to help you know what it will look like at runtime.
The value “Answer” will never show up in the real app. Handy!
You will not be creating a landscape alternative for activity_cheat.xml, but there is a way to preview how the default layout will appear in landscape.
In the preview tool window, find the button in the toolbar above the preview pane that looks like a device with curved arrows. Click this button to change the orientation of the preview (Figure 5.6).
The default layout works well enough in both orientations, so let’s move on to fleshing out the activity subclass.
In the project tool window, find the com.bignerdranch.android.geoquiz Java package and open the CheatActivity class, which is in the CheatActivity.java file.
This class already includes a basic implementation of onCreate(Bundle) that passes the resource ID of the layout defined in activity_cheat.xml to setContentView(…).
CheatActivity will eventually do more in its onCreate(Bundle) method. For now, let’s take a look at another thing the New Activity wizard did for you: declaring CheatActivity in the application’s manifest.
The manifest is an XML file containing metadata that describes your application to the Android OS. The file is always named AndroidManifest.xml, and it lives in the app/manifests directory of your project.
In the project tool window, find and open AndroidManifest.xml. You can also use Android Studio’s Quick Open dialog by pressing Command+Shift+O (Ctrl+Shift+N) and starting to type the filename. Once it has guessed the right file, press Return to open it.
Every activity in an application must be declared in the manifest so that the OS can access it.
When you used the New Project wizard to create QuizActivity, the wizard declared the activity for you. Likewise, the New Activity wizard declared CheatActivity by adding the XML highlighted in Listing 5.3.
Listing 5.3 Declaring CheatActivity
in the manifest (AndroidManifest.xml
)
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bignerdranch.android.geoquiz" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".QuizActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".CheatActivity"> </activity> </application> </manifest>
The android:name
attribute is required, and the dot at the start of this attribute’s
value tells the OS that this activity’s class is in the package specified in the package
attribute in the manifest
element at the top of the file.
You will sometimes see a fully qualified android:name
attribute, like android:name="com.bignerdranch.android.geoquiz.CheatActivity"
. The long-form notation is identical to the version in Listing 5.3.
There are many interesting things in the manifest, but, for now, let’s stay focused on getting CheatActivity up and running. You will learn about the different parts of the manifest in later chapters.
The plan is for the user to press a button in QuizActivity to get an instance of CheatActivity on screen. So you need new buttons in layout/activity_quiz.xml and layout-land/activity_quiz.xml.
In the default layout, add the new button as a direct child of the root LinearLayout. Its definition should come right before the NEXT button.
Listing 5.4 Adding a cheat button to the default layout (layout/activity_quiz.xml
)
... </LinearLayout> <Button android:id="@+id/cheat_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/cheat_button"/> <Button android:id="@+id/next_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/next_button" android:drawableRight="@drawable/arrow_right" android:drawablePadding="4dp"/> </LinearLayout>
In the landscape layout, have the new button appear at the bottom and center of the root FrameLayout.
Listing 5.5 Adding a cheat button to the landscape layout (layout-land/activity_quiz.xml
)
... </LinearLayout> <Button android:id="@+id/cheat_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:text="@string/cheat_button" /> <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" /> </FrameLayout>
Reopen QuizActivity.java. Add a variable, get a reference, and set a View.OnClickListener stub for the CHEAT! button.
Listing 5.6 Wiring up the cheat button (QuizActivity.java
)
public class QuizActivity extends AppCompatActivity { ... private Button mNextButton; private Button mCheatButton; private TextView mQuestionTextView; ... @Override protected void onCreate(Bundle savedInstanceState) { ... mNextButton = (Button) findViewById(R.id.next_button); mNextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCurrentIndex = (mCurrentIndex + 1) % mQuestionBank.length; updateQuestion(); } }); mCheatButton = (Button)findViewById(R.id.cheat_button); mCheatButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Start CheatActivity } }); updateQuestion(); } ... }
Now you can get to the business of starting CheatActivity.
44.192.73.68