• No results found

protected void onStart() {

Software Engineering Observation 4

Step 7: Setting the Properties of the Button s

62 protected void onStart() {

63 super.onStart();

64

65 if (preferencesChanged) {

66 // now that the default preferences have been set,

67 // initialize MainActivityFragment and start the quiz

68 69 70

Fig. 4.27 | MainActivity overridden Activity method onStart. (Part 1 of 2.)

MainActivityFragment quizFragment = (MainActivityFragment) getSupportFragmentManager().findFragmentById(

R.id.quizFragment);

ptg16518503

4.6.5 Overridden

Activity

Method

onCreateOptionsMenu

Overridden Activity method onCreateOptionsMenu (Fig. 4.28) initializes the Activi- ty’s options menu—this method and method onOptionsItemSelected (Section 4.6.6) were autogenerated by Android Studio’s Blank Activity template. The system passes in the

Menu object where the options will appear. In this app, we want to show the menu only when the app is running in portrait orientation, so we modified this method to check the device’s orientation. Line 84 uses the Activity’s Resources object (returned by inherited method getResources) to obtain a Configuration object (returned by method getCon- figuration) that represents the device’s current configuration. This object’s public in- stance variable orientation contains either Configuration.ORIENTATION_PORTRAIT or

Configuration.ORIENTATION_LANDSCAPE. If the device is in portrait orientation (line 87), line 89 creates the menu from menu_main.xml—the default menu resource that the IDE defined when you created the project. Inherited Activity method getMenuInflater re- turns a MenuInflater on which we call inflate with two arguments—the resource ID of the menu resource that populates the menu and the Menu object in which the menu items will be placed. Returning true from onCreateOptionsMenu indicates that the menu should be displayed. 71 quizFragment.updateGuessRows( 72 ); 73 quizFragment.updateRegions( 74 PreferenceManager.getDefaultSharedPreferences(this)); 75 quizFragment.resetQuiz(); 76 preferencesChanged = false; 77 } 78 } 79

80 // show menu if app is running on a phone or a portrait-oriented tablet

81 @Override

82

83 // get the device's current orientation

84 85

86 // display the app's menu only in portrait orientation

87 {

88 // inflate the menu

89 getMenuInflater().inflate(R.menu.menu_main, menu);

90 return true; 91 } 92 else 93 return false; 94 } 95

Fig. 4.28 | MainActivity overridden Activity method onCreateOptionsMenu.

Fig. 4.27 | MainActivity overridden Activity method onStart. (Part 2 of 2.)

PreferenceManager.getDefaultSharedPreferences(this)

public boolean onCreateOptionsMenu(Menu menu) {

int orientation = getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_PORTRAIT)

ptg16518503

4.6 MainActivity Class 145

4.6.6 Overridden

Activity

Method

onOptionsItemSelected Method onOptionsItemSelected (Fig. 4.29) is called when a menu item is selected. In this app, the default menu provided by the IDE when you created the project contains only the

Settings menu item, so if this method is called, the user selected Settings. Line 99 creates an

explicit Intent for launching the SettingsActivity. The Intent constructor used here re- ceives the Context from which the Activity will be launched and the class representing the

Activity to launch (SettingsActivity.class). We then pass this Intent to the inherited

Activity method startActivity to launch the Activity (line 100).

4.6.7 Anonymous Inner Class That Implements

OnSharedPreferenceChangeListener

The preferencesChangeListener objec (Fig. 4.30) is an anonymous-inner-class object that implements the OnSharedPreferenceChangeListener interface. This object was reg- istered in method onCreate to listen for changes to the app’s SharedPreferences. When a change occurs, method onSharedPreferenceChanged sets preferencesChanged to true

(line 111), then gets a reference to the MainActivityFragment (lines 113–115) so that the quiz can be reset with the new preferences. If the CHOICES preference changed, lines 118– 119 call the MainActivityFragment’s updateGuessRows and resetQuiz methods.

96 // displays the SettingsActivity when running on a phone

97 @Override 98 99 100 101 return super.onOptionsItemSelected(item); 102 } 103

Fig. 4.29 | MainActivity overridden Activity method onOptionsItemSelected.

104 // listener for changes to the app's SharedPreferences

105 106 107 108 109 110

111 preferencesChanged = true; // user changed app settings

112 113 114 115 116

117 if (key.equals(CHOICES)) { // # of choices to display changed

118 quizFragment.updateGuessRows(sharedPreferences);

Fig. 4.30 | Anonymous Inner class that implements OnSharedPreferenceChangeListener. (Part 1 of 2.)

public boolean onOptionsItemSelected(MenuItem item) {

Intent preferencesIntent = new Intent(this, SettingsActivity.class); startActivity(preferencesIntent);

private OnSharedPreferenceChangeListener preferencesChangeListener = new OnSharedPreferenceChangeListener() {

// called when the user changes the app's preferences

@Override

public void onSharedPreferenceChanged(

SharedPreferences sharedPreferences, String key) {

MainActivityFragment quizFragment = (MainActivityFragment) getSupportFragmentManager().findFragmentById(

R.id.quizFragment);

ptg16518503

If the REGIONS preference changed, lines 122–123 get the Set<String> containing the enabled regions. SharedPreferences method getStringSet returns a Set<String> for the specified key. The quiz must have at least one region enabled, so if the Set<String> is not empty, lines 126–127 call the MainActivityFragment’s updateRegions and

resetQuiz methods.

If the Set<String> is empty, lines 131–135 update the REGIONS preference with North America set as the default region. To obtain the default region’s name, line 133 calls

Activity’s inherited method getString, which returns the String resource for the spec- ified resource ID (R.string.default_region).

To change a SharedPreferences object’s contents, first call its edit method to obtain a SharedPreferences.Editor object (lines 131–132), which can add key–value pairs to, remove key–value pairs from, and modify the value associated with a particular key in a

SharedPreferences file. Line 134 calls SharedPreferences.Editor method put- StringSet to store the contents of regions (the Set<String>). Line 135 commits (saves) the changes by calling SharedPreferences.Editor method apply, which immediately makes the changes to the in-memory representation of the SharedPreferences, and asyn-

119 quizFragment.resetQuiz();

120 }

121 else if (key.equals(REGIONS)) { // regions to include changed

122 123 124

125 if (regions != null && regions.size() > 0) {

126 quizFragment.updateRegions(sharedPreferences); 127 quizFragment.resetQuiz(); 128 } 129 else { 130 131 132 133 134 135 136 137 138 139 140 } 141 } 142 143 Toast.makeText(MainActivity.this, 144 R.string.restarting_quiz, 145 Toast.LENGTH_SHORT).show(); 146 } 147 }; 148 }

Fig. 4.30 | Anonymous Inner class that implements OnSharedPreferenceChangeListener. (Part 2 of 2.)

Set<String> regions =

sharedPreferences.getStringSet(REGIONS, null);

// must select one region--set North America as default

SharedPreferences.Editor editor = sharedPreferences.edit();

regions.add(getString(R.string.default_region)); editor.putStringSet(REGIONS, regions);

editor.apply();

Toast.makeText(MainActivity.this,

R.string.default_region_message, Toast.LENGTH_SHORT).show();

ptg16518503

4.7 MainActivityFragment Class 147 chronously writes the changes to the file in the background. There is also a commit method that writes the writes the changes to the file synchronously (immediately).

Lines 137–139 use a Toast to indicate that the default region was set. Toast method

makeText receives as arguments the Context on which the Toast is displayed, the message to display and the duration for which the Toast will be displayed. Toast method show dis- plays the Toast. Regardless of which preference changed, lines 143–145 display a Toast

indicating that the quiz will be reset with the new preferences. Figure 4.31 shows the

Toast that appears after the user changes the app’s preferences.

4.7

MainActivityFragment Class

Class MainActivityFragment (Figs. 4.32–4.42)—a subclass of the Android Support Li- brary’s Fragment class (package android.support.v4.app)—builds the Flag Quiz’s GUI

and implements the quiz’s logic.

4.7.1

package

and

import

Statements

Figure 4.32 shows the MainActivityFragmentpackage statement and import statements. Lines 5–36 import the various Java and Android classes and interfaces that the app uses. We’ve highlighted the key import statements, and we discuss the corresponding classes and interfaces in Section 4.3 and as they’re encountered in Sections 4.7.2–4.7.11.

Fig. 4.31 | Toast displayed after a preference is changed.

1 // MainActivityFragment.java

2 // Contains the Flag Quiz logic

3 package com.deitel.flagquiz; 4 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.security.SecureRandom; 8 9 10 11 12 13 14 15 16 17 18 19 20

Fig. 4.32 | MainActivityFragmentpackage statement, import statements. (Part 1 of 2.)

import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.AssetManager; import android.graphics.drawable.Drawable; WOW! eBook

ptg16518503

4.7.2 Fields

Figure 4.33 lists class MainActivityFragment’s static and instance variables. The con- stant TAG (line 40) is used when we log error messages using class Log (Fig. 4.38) to distin- guish this Activity’s error messages from others that are being written to the device’s log. The constant FLAGS_IN_QUIZ (line 42) represents the number of flags in the quiz.

21 import android.os.Bundle; 22 23 24 25 26 import android.view.LayoutInflater; 27 import android.view.View; 28 29 30 import android.view.ViewGroup; 31 32 33 import android.widget.Button; 34 import android.widget.ImageView; 35 import android.widget.LinearLayout; 36 import android.widget.TextView; 37

38 public class MainActivityFragment extends Fragment {

39 // String used when logging error messages

40 private static final String TAG = "FlagQuiz Activity";

41