9.2: Adding Settings to an App
Contents:
- What you should already KNOW
- What you will LEARN
- What you will DO
- App overview
- Task 1: Add a switch setting to an app
- Task 2: Using the Settings Activity template
- Coding challenges
- Summary
- Related Concept
- Learn more
Apps often include settings that allow users to modify app features and behaviors. For example, some apps allow users to set their home locations, default units for measurements, dining options, and other settings that apply to the entire app. Settings are usually accessed infrequently, because once a user changes a setting, such as a home location, they rarely need to go back and change it again.
Users expect to navigate to app settings by tapping Settings in side navigation, such as a navigation drawer as shown on the left side of the figure below, or in the options menu in the app bar, shown on the right side of the figure below.
In the figure above:
- Settings in side navigation (a navigation drawer)
- Settings in the options menu of the app bar
In this practical you will add a settings activity to an app. Users will be able to navigate to the app settings by tapping Settings, which will be located in the options menu in the app bar.
What you should already KNOW
From the previous practicals, you should be able to:
- Add an activity to an app.
- Design layouts with buttons and text views.
- Extract string resources and edit string and string array values.
- Create an options menu in the app bar.
- Add and edit the menu items in the options menu.
- Add the event handler for menu item clicks.
- Edit the AndroidManifest.xml file to add Up navigation for a second activity.
- Read preferences from
sharedPreferences
.
What you will LEARN
You will learn to:
- Add an activity and understand the use of fragments for managing settings.
- Create an XML resource file of settings with their attributes.
- Create navigation to the settings activity.
- Set the default values of settings.
- Read the settings values changed by the user.
- Customize the Settings Activity template for your own use.
What you will DO
In this practical, you will:
- Create an app that includes Settings in the options menu.
- Add "Settings option" as a toggle switch.
- Add code to set the default value for the setting, and access the setting value after it has changed.
- Use and customize the Android Studio Settings Activity template.
App overview
Android Studio provides a shortcut for setting up an options menu with Settings. If you start an Android Studio project for a smartphone or tablet using the Basic Activity template, the new app includes Settings as shown below:
The template also includes a floating action button in the lower right corner of the screen with an envelope icon. You can ignore this button for this practical, as you won't be using it.
You'll start by creating an app named AppWithSettings using the Basic Activity template, and add a settings activity that provides one toggle switch setting that the user can turn on or off:
You will add code to read the setting and perform an action based on its value. For the sake of simplicity, the action will be to display a toast message with the value of the setting.
In the second task, you will add the standard Settings Activity template provided by Android Studio to the DroidCafe app you created in a previous lesson. The Settings Activity template is pre-populated with settings you can customize for an app, and provides a different layout for smartphones and tablets:
Smartphones: A main Settings screen with a header link for each group of settings, such as General for general settings, as shown below.
Tablets: A master/detail screen layout with a header link for each group on the left (master) side, and the group of settings on the right (detail) side, as shown in the figure below.
All you need to do to customize the template is change the headers, setting titles, setting descriptions, and values for the settings, and write the code you would normally write to use the values of the settings.
The Droid Cafe app was created in a previous lesson from the Basic Activity template, which provides an options menu in the app bar for placing the Settings option. You will customize the supplied Settings Activity template by changing a single setting's title, description, values, and default values. You will add code to read the setting's value after the user changes it, and display that value.
Task 1: Add a switch setting to an app
In this task, you will:
- Create a new project based on the Basic Activity template (which provides an options menu).
- Add a toggle switch setting with attributes in a preference XML file.
- Add an activity for settings and a fragment for a specific setting. You will use the
PreferenceFragmentCompat
version of PreferenceFragment in order to maintain compatibility withAppCompatActivity
. You will also add the android.support:preference-v7 library. - Connect the Settings item in the options menu to the settings activity.
1.1 Create the project and add the xml directory and resource file
- In Android Studio, create a new project with the following parameters:
Attribute
Value
Application Name
AppWithSettings
Company Name
android.example.com (or your own domain)
Phone and Tablet Minimum SDK
API15: Android 4.0.3 IceCreamSandwich
Use a Fragment?
Leave unchecked
Template
Basic Activity
- Run the app, and tap the overflow icon in the app bar to see the options menu, as shown in the figure below. The only item in the options menu is Settings.
- Create a new resource directory to hold the XML file containing the settings:
- Select the res directory in the Project: Android view, and choose File > New > Android Resource Directory. The New Resource Directory dialog appears.
- In the Resource type drop-down menu, choose xml. The Directory name automatically changes to
xml
. - Click OK.
- The xml directory appears in the Project: Android view inside the res directory. Select the xml directory and choose File > New > XML resource file (or right-click the xml directory and choose New > XML resource file).
- Enter the name of the XML file, preferences, in the File name field, and click OK. The preferences.xml file appears inside the xml directory, and the layout editor appears, as shown in the figure below.
In the figure above:
- The preferences.xml file inside the xml directory.
- The layout editor showing the preferences.xml contents.
1.2 Add the XML preference and attributes for the setting
Drag a SwitchPreference from the Palette pane on the left side to the top of the layout, as shown in the figure below.
Change the values in the Properties pane on the right side of the layout editor as follows (refer to the figure below):
- defaultValue: true
- key: example_switch
- title: Settings option
- summary: Turn this option on or off
Click the Text tab at the bottom of the layout editor to edit the XML code:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <SwitchPreference android:defaultValue="true" android:title="Settings option" android:key="example_switch" android:summary="Turn this option on or off" /> </PreferenceScreen>
The Properties values you entered represent XML attributes:
android:defaultValue
: The default value of the setting when the app starts for the first time.android:title
: The title of the setting. For aSwitchPreference
, the title appears to the left of the toggle switch.android:key
: The key to use for storing the setting value. Each setting has a corresponding key-value pair that the system uses to save the setting in a default SharedPreferences file for your app's settings.android:summary
: The text summary appears underneath the setting.
Extract the string resources for the
android:title
andandroid:summary
attribute values to@string/switch_title
and@string/switch_summary
.Change
<SwitchPreference
in the code to<android.support.v7.preference.SwitchPreferenceCompat
:<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <android.support.v7.preference.SwitchPreferenceCompat ... /> </PreferenceScreen>
In order to use the
PreferenceFragmentCompat
version of PreferenceFragment, you must also use the android.support.v7 version of SwitchPreference (SwitchPreferenceCompat
).The
SwitchPreferenceCompat
line above may show a yellow light bulb icon with a warning, but you can ignore it.Open the styles.xml file, and add the following
preferenceTheme
declaration to theAppTheme
:<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> ... <item name="preferenceTheme">@style/PreferenceThemeOverlay</item> </style>
In order to use the
PreferenceFragmentCompat
version of PreferenceFragment, you must also declarepreferenceTheme
with thePreferenceThemeOverlay
style to the app theme.- Open the build.gradle (Module: app) file, and add the following to the
dependencies
section:dependencies { ... compile 'com.android.support:preference-v7:25.0.1' }
The above adds the android.support:preference-v7 library in order to use the PreferenceFragmentCompat
version of PreferenceFragment.
1.3 Add an activity for settings and a fragment for a specific setting
In order to create a Settings activity that provides a UI for settings, add an Empty Activity to the app:
- Select app at the top of the Project: Android view.
- Choose New > Activity > Empty Activity.
- Name the activity SettingsActivity.
- Uncheck the option to generate a layout file (you don't need one).
- Leave checked the Backwards Compatibility (AppCompat) option.
- The Package name should already be set to com.example.android.projectname, and the Target Source Set should be set to main. If not, make these selections in the drop-down menus.
- Click Finish.
The result is the following class definition in SettingsActivity:
public class SettingsActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } }
Add a blank fragment for a group of similar settings (without a layout, factory methods, or interface callbacks) to the app, in order to swap them into the Settings activity screen when needed:
- Select app at the top of the Project: Android view again.
- Choose New > Fragment > Fragment (Blank).
- Name the fragment SettingsFragment.
- Uncheck the option to generate a layout file (you don't need one).
- Uncheck the option to include fragment factory methods.
- Uncheck the option to include interface callbacks.
- Click Finish.
The result is the following class definition in SettingsFragment:
public class SettingsFragment extends Fragment { public SettingsFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setText(R.string.hello_blank_fragment); return textView; } }
Change the class definition of SettingsFragment to extend
PreferenceFragmentCompat
:public class SettingsFragment extends PreferenceFragmentCompat { ... }
You use a specialized Fragment subclass to display a list of settings. The best practice is to use a regular Activity that hosts a PreferenceFragment that displays the app settings. Fragments like PreferenceFragment provide a more flexible architecture for your app, compared to using activities alone. A fragment is like a modular section of an activity—it has its own lifecycle and receives its own input events, and you can add or remove a fragment while the activity is running.
Use the
PreferenceFragmentCompat
version of PreferenceFragment with an activity that extends AppCompatActivity. In order to extend the fragment, you may have to add the following import statement:import android.support.v7.preference.PreferenceFragmentCompat;
Replace the entire
onCreateView()
method in the fragment with thisonCreate()
method:@Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { }
The reason why you replace
onCreateView()
withonCreatePreferences()
in SettingsFragment is because you will be adding this fragment to the existing SettingsActivity to display preferences, rather than showing a separate fragment screen. Adding it to the existing activity makes it easy to add or remove a fragment while the activity is running. The preference fragment is rooted at the PreferenceScreen usingrootKey
.You can safely remove the empty constructor from the fragment as well, since the fragment is not displayed by itself:
public SettingsFragment() { // Required empty public constructor }
At the end of the
onCreatePreferences()
method in SettingsFragment, you need to associate with this fragment the preferences.xml settings resource you just created. Add a call to setPreferencesFromResource() passing the id of the XML file (R.xml.preferences)
and therootKey
to identify the preference root inPreferenceScreen
:setPreferencesFromResource(R.xml.preferences, rootKey);
The
onCreatePreferences()
method should now look like this:@Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.preferences, rootKey); }
Add the following code to the end of the SettingsActivity
onCreate()
method so that the fragment is displayed as the main content:getSupportFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()) .commit();
The above code is the typical pattern used to add a fragment to an activity so that the fragment appears as the main content of the activity. You use:
getFragmentManager()
if the class extendsActivity
and the fragment extendsPreferenceFragment
.getSupportFragmentManager()
if the class extendsAppCompatActivity
and the fragment extendsPreferenceFragmentCompat
.
The entire
onCreate()
method in SettingsActivity should now look like the following:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()) .commit(); }
1.4 Connect the Settings menu item to the settings activity
Use an intent
to launch the SettingsActivity from the MainActivity.
- Find the
if
block in theonOptionsItemSelected()
method in MainActivity, which handles the tap on Settings in the options menu:if (id == R.id.action_settings) { return true; }
- Add an
intent
to theif
block to launch the SettingsActivity:if (id == R.id.action_settings) { Intent intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; }
- Add Up-button navigation to
SettingsActivity
by editing its declaration in the AndroidManifest.xml file to define the activity's parent asMainActivity
.- Find the
SettingsActivity
declaration in AndroidManifest.xml:<activity android:name=".SettingsActivity"></activity>
- Change the declaration to the following:
<activity android:name=".SettingsActivity" android:label="Settings" android:parentActivityName=".MainActivity"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"/> </activity>
- Find the
- Run the app. Tap the overflow icon for the options menu (as shown on the left side of the figure below), and tap Settings to see the settings activity (as shown in the center of the figure below). Tap the Up button in the app bar of the settings activity, shown on the right side of the figure below, to return to the main activity.
1.5 Save the default values in shared preferences
Although the default value for the toggle switch setting has already been set in the android:defaultValue
attribute (in Step 1.2 of this task), the app must save the default value in the SharedPreferences file for each setting when the user first opens the app. Follow these steps to set the default value for the toggle switch:
In MainActivity, add the following to the end of the existing
onCreate()
method:protected void onCreate(Bundle savedInstanceState) { ... PreferenceManager.setDefaultValues(this, R.xml.preferences, false); }
The above code ensures that the settings are properly initialized with their default values. The
setDefaultValues()
method takes three arguments:- The app context, such as
this
. - The resource ID (
preferences
) for the XML resource file with one or more settings. - A boolean indicating whether the default values should be set more than once. When
false
, the system sets the default values only if this method has never been called in the past. As long as you set this third argument tofalse
, you can safely call this method every time the main activity starts without overriding the user's saved settings values. However, if you set it totrue
, the method will override any previous values with the defaults.
1.6 Read the changed settings value from shared preferences
When the app starts, the MainActivity's onCreate()
method can read setting values that have changed, and use the changed values rather than the default values.
Each setting is identified using a key-value pair. The Android system uses this key-value pair when saving or retrieving settings from a SharedPreferences file for your app. When the user changes a setting, the system updates the corresponding value in the SharedPreferences file. To use the value of the setting, the app can use the key to get the setting from the SharedPreferences file.
Follow these steps to add that code:
- Before adding code to read the setting value, create a static string variable in SettingsActivity to hold the key for the value:
public class SettingsActivity extends AppCompatActivity { public static final String KEY_PREF_EXAMPLE_SWITCH = "example_switch"; ... }
In the
onCreate()
method in MainActivity, and add the following at end of the method:protected void onCreate(Bundle savedInstanceState) { ... SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); Boolean switchPref = sharedPref.getBoolean (SettingsActivity.KEY_PREF_EXAMPLE_SWITCH, false); }
The above code snippet uses
PreferenceManager.getDefaultSharedPreferences(this)
to get the setting as a SharedPreferences object (sharedPref
).getBoolean()
to get the Boolean value of the setting that uses the key (KEY_PREF_EXAMPLE_SWITCH
defined in SettingsActivity) and assign it toswitchPref
. If there is no value for the key, thegetBoolean()
method sets the setting value (switchPref
) tofalse
. For other values such as strings, integers, or floating point numbers, you can use thegetString()
,getInt()
, orgetFloat()
methods respectively.
Add a
Toast.makeText()
method toonCreate()
that displays the value of theswitchPref
setting in a toast:Toast.makeText(this, switchPref.toString(), Toast.LENGTH_SHORT).show();
- Run the app and then follow these steps:
- Tap Settings to see the settings activity.
- Tap the setting to change the toggle from on to off, as shown on the left side of the figure below.
- Tap the Up button in the settings activity to return to the main activity. The toast message should appear in the main activity with the value of the setting, as shown on the right side of the figure below.
- Repeat these steps to see the toast message change as you change the setting.
Whenever the MainActivity starts or restarts, the onCreate()
method should read the setting values in order to use them in the app. The Toast.makeText()
method would be replaced with a method that initializes the settings.
You now have a working settings activity in your app.
Solution code:
Android Studio project: AppWithSettings
Task 2: Using the Settings Activity template
If you need to build several sub-screens of settings and you want to take advantage of tablet-sized screens as well as maintain compatibility with older versions of Android for tablets, Android Studio provides a shortcut: the Settings Activity template.
In the previous task you learned how to use an empty settings activity and a blank fragment in order to add a setting to an app. Task 2 will now show you how to use the Settings Activity template supplied with Android Studio to:
- Divide multiple settings into groups.
- Customize the settings and their values.
- Display a main Settings screen with a header link for each group of settings, such as General for general settings, as shown in the figure below.
- Display a master/detail screen layout with a header link for each group on the left (master) side, and the group of settings on the right (detail) side, as shown in the figure below.
In a previous practical you created an app called Droid Cafe using the Basic Activity template, which provides an options menu in the app bar as shown below.
In the above figure:
- App bar.
- Options menu action icons.
- Overflow button.
- Options overflow menu.
Android Studio project: To start the project from where you left off in the previous practical, download the Android Studio project DroidCafe.
2.1 Explore the Settings Activity template
To include the Settings Activity template in your app project in Android Studio, follow these steps:
- Copy the DroidCafe project folder, rename it to DroidCafeWithSettings, and refactor it. (See the Appendixfor instructions on copying a project.) Run the app to make sure it runs properly.
- Select app at the top of the Project: Android view, and choose New > Activity > Settings Activity.
- In the dialog that appears, accept the Activity Name (SettingsActivity is the suggested name) and the Title (Settings).
- Click the three dots at the end of the Hierarchical Parent field and choose MainActivity as the parent activity, so that the Up button in the Settings Activity returns the user to the MainActivity. Choosing the parent activity automatically updates the AndroidManifest.xml file to support Up button navigation.
- Click Finish.
The Settings Activity template not only provides layouts for smartphone-sized and tablet-sized screens, but also provides the function of listening to a settings change, and changing the summary to reflect the settings change. For example, if you change the "Add friends to messages" setting (the choices are Always, When possible, or Never), the choice you make appears in the summary underneath the setting:
In general, you need not change the Settings Activity template code in order to customize the activity for the settings you want in your app. You can customize the settings titles, summaries, possible values, and default values without changing the template code, and even add more settings to the groups that are provided.
You use the Settings Activity template code as-is. To make it work for your app, add code to the Main Activity to set the default settings values, and to read and use the settings values, as shown later in this task.
The Settings Activity template creates the following for you:
XML files in the res > xml directory, which you can add to or customize for the settings you want.
- pref_data_sync.xml: PreferenceScreen layout for "Data & sync" settings.
- pref_general.xml: PreferenceScreen layout for "General" settings.
- pref_headers.xml: Layout of headers for the Settings main screen.
- pref_notification.xml: PreferenceScreen layout for "Notifications" settings.
The above XML layouts use various subclasses of the Preference class rather than View objects, and direct subclasses provide containers for layouts involving multiple settings. For example, PreferenceScreen represents a top-level Preference that is the root of a Preference hierarchy. The above files use PreferenceScreen at the top of each screen of settings. Other Preference subclasses for settings provide the appropriate UI for users to change the setting. For example:
- CheckBoxPreference: A checkbox for a setting that is either enabled or disabled.
- ListPreference: A dialog with a list of radio buttons.
- SwitchPreference: A two-state toggleable option (such as on/off or true/false).
- EditTextPreference: A dialog with an EditText widget.
- RingtonePreference: A dialog with ringtones on the device.
Tip: You can edit the XML files to change the default settings to settings you need for your app.
String resources in the strings.xml file in the res > values directory, which you can customize for the settings you want.
All strings used in the Settings Activity, such as the titles for settings, string arrays for lists, and descriptions for settings, are defined as string resources at the end of this file. They are marked by comments such as
<!-- Strings related to Settings -->
and<!-- Example General settings -->
.Tip: You can edit these strings to customize the settings you need for your app.
SettingsActivity in the java > com.example.android.projectname directory, which you can use as is.
This is the activity that displays the settings.
SettingsActivity
extendsAppCompatPreferenceActivity
for maintaining compatibility with older versions of Android.AppCompatPreferenceActivity in the java > com.example.android.projectname directory, which you use as is.
This activity is a helper class that SettingsActivity uses to maintain backwards compatibility with previous versions of Android.
2.2 Add the Settings menu item and connect it to the activity
As you learned in a previous practical, you can edit the menu_main.xml file in the res > menu directory for the options menu to add or remove menu items.
Edit the menu_main.xml file to add another menu item called Settings with the new resource id
action_settings
:<item android:id="@+id/action_settings" android:orderInCategory="50" android:title="Settings" app:showAsAction="never" />
Specify
"never"
for theapp:showAsAction
attribute so that Settings appears only in the overflow options menu and not in the app bar itself, since it should not be used often.Specify
"50"
for theandroid:orderInCategory
attribute so that Settings appears below Favorites (set to"40"
) but above Contact (set to"100"
).- Extract the string resource for
"Settings"
in theandroid:title
attribute to the resource namesettings
. In MainActivity, find the
switch-case
block in theonOptionsItemSelected()
method which handles the tap on items in the options menu:public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_order: displayToast(getString(R.string.action_order_message)); return true; case R.id.action_status: displayToast(getString(R.string.action_status_message)); return true; case R.id.action_favorites: displayToast(getString(R.string.action_favorites_message)); return true; case R.id.action_contact: displayToast(getString(R.string.action_contact_message)); return true; } return super.onOptionsItemSelected(item); }
Use an
intent
to launch the SettingsActivity from the MainActivity. Add theintent
to the end of theswitch case
block:... case R.id.action_settings: Intent intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); }
Run the app using a smartphone or smartphone emulator so that you can see how the Settings Activity template handles the smartphone screen size, and follow these steps:
Tap the overflow icon for the options menu, and tap Settings to see the settings activity, as shown on the left side of the figure below.
Tap each setting header (General, Notifications, and Data & sync), as shown in the center of the figure below, to see the group of settings on each child screen of the Settings screen, shown on the right side of the figure below.
Tap the Up button in the settings activity to return to the main activity.
2.3 Customize the settings provided by the template
To customize the settings provided by the Settings Activity template, edit the string and string array resources in the strings.xml file and the layout attributes for each setting in the files in the xml directory. In this step you will change the "Data & sync" settings.
Open the strings.xml file in the res > values directory, and scroll the contents to the
<!-- Example settings for Data & Sync -->
comment:<!-- Example settings for Data & Sync --> <string name="pref_header_data_sync">Data & sync</string> <string name="pref_title_sync_frequency">Sync frequency</string> <string-array name="pref_sync_frequency_titles"> <item>15 minutes</item> <item>30 minutes</item> <item>1 hour</item> <item>3 hours</item> <item>6 hours</item> <item>Never</item> </string-array> <string-array name="pref_sync_frequency_values"> <item>15</item> <item>30</item> <item>60</item> <item>180</item> <item>360</item> <item>-1</item> </string-array> ...
- Edit the
pref_header_data_sync
string resource, which is set toData & sync
(the&
is HTML code for an ampersand). Change the value to Account (without quotation marks). Refactor the resource name by following these steps (the app will still work without refactoring the names, but refactoring makes the code easier to understand):
- Control-click (or right-click) the pref_header_data_sync resource name and choose Refactor > Rename.
- Change the name to pref_header_account, click the option to search in comments and strings, and click Refactor.
Edit the
pref_title_sync_frequency
string resource (which is set toSync frequency
) to Market.- Refactor > Rename the resource name to pref_title_account as you did previously.
- Refactor > Rename the string array resource name
pref_sync_frequency_titles
to pref_market_titles. - Change each value in the
pref_market_titles
string array (15 minutes
,30 minutes
,1 hour
, etc.) to be the titles of markets, such as United States, Canada, etc., rather than frequencies:<string-array name="pref_market_titles"> <item>United States</item> <item>Canada</item> <item>United Kingdom</item> <item>India</item> <item>Japan</item> <item>Other</item> </string-array>
- Refactor > Rename the string array resource name
pref_sync_frequency_values
to pref_market_values. - Change each value in the
pref_market_values
string array (15
,30
,60
, etc.) to be values for the markets—abbreviations such as US, CA, etc.:<string-array name="pref_market_values"> <item>US</item> <item>CA</item> <item>UK</item> <item>IN</item> <item>JA</item> <item>-1</item> </string-array>
- Scroll down to the
pref_title_system_sync_settings
string resource, and edit the resource (which is set toSystem sync settings
) to Account settings. - Refactor > Rename the string array resource name
pref_title_system_sync_settings
to pref_title_account_settings. - Open the pref_data_sync.xml file. The
ListPreference
in this layout defines the setting you just changed. Note that the string resources for theandroid:entries
,android:entryValues
andandroid:title
attributes are now changed to the values you supplied in the previous steps:<ListPreference android:defaultValue="180" android:entries="@array/pref_market_titles" android:entryValues="@array/pref_market_values" android:key="sync_frequency" android:negativeButtonText="@null" android:positiveButtonText="@null" android:title="@string/pref_title_account" />
- Change the
android:defaultValue
attribute:android:defaultValue="US"
Since the key for this setting preference ("sync_frequency"
) is hard-coded elsewhere in the Java code, don't change the android:key
attribute—keep using "sync_frequency"
as the key for this setting in this example. If you are thoroughly customizing the settings for a real-world app, you would spend the time changing the hard-coded keys throughout the code.
2.4 Add code to set the default values for the settings
Find the onCreate()
method in MainActivity, and add the following PreferenceManager.setDefaultValues
statements at the end of the method:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
PreferenceManager.setDefaultValues(this, R.xml.pref_general, false);
PreferenceManager.setDefaultValues(this, R.xml.pref_notification, false);
PreferenceManager.setDefaultValues(this, R.xml.pref_data_sync, false);
}
The default values are already specified in the XML file with the android:defaultValue
attribute, but the above statements ensure that the Shared Preferences file is properly initialized with the default values. The setDefaultValues()
method takes three arguments:
- The app context, such as
this
. - The resource ID for the settings layout XML file which includes the default values set by the
android:defaultValue
attribute. - A boolean indicating whether the default values should be set more than once. When
false
, the system sets the default values only if this method has never been called in the past. As long as you set this third argument tofalse
, you can safely call this method every time your activity starts without overriding the user's saved settings values by resetting them to the default values. However, if you set it totrue
, the method will override any previous values with the defaults.
2.5 Add code to read values for the settings
Add the following code at the end of the MainActivity
onCreate()
method. You can add it immediately after the code you added in the previous step to set the defaults for the settings:... SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); String marketPref = sharedPref.getString("sync_frequency", "-1"); Toast.makeText(this, marketPref, Toast.LENGTH_SHORT).show(); }
As you learned in the previous task, you use
PreferenceManager.getDefaultSharedPreferences(this)
to get the setting as a SharedPreferences object (marketPref
). You then usegetString()
to get the string value of the setting that uses the key (sync_frequency
) and assign it tomarketPref
. If there is no value for the key, thegetString()
method sets the setting value ofmarketPref
to-1
, which is the value ofOther
in thepref_market_values
array.- Run the app, again using a smartphone or smartphone emulator. When the app's main screen first appears, you see a toast message at the bottom of the screen. The first time you run the application, you should see "-1" displayed in the toast because you haven't changed the setting yet.
- Tap Settings in the options menu, and tap Account in the Settings screen. Choose Canada under "Market" as shown below:
Tap the Up button in the app bar to return to the Settings screen, and tap it again to return to the main screen. You should see a toast message with "CA" (for Canada):
You have successfully integrated the Settings Activity with the Droid Cafe app.
- Now run the app on a tablet or tablet emulator. Because a tablet has a physically larger screen, the Android runtime takes advantage of the extra space. On a tablet, the settings and details are displayed on the same screen making it easier for users to manage their settings.
Solution code
Android Studio project: DroidCafeWithSettings (Includes coding challenge #1.)
Android Studio project: DroidCafeWithSettingsChallenge (Includes coding challenge #2.)
Coding challenges
Challenge 1: Add code to DroidCafeWithSettings that reads the value of the toggle switch "Enable social recommendations" on the General child screen of Settings, and displays its value along with the "Market" setting in the same toast message on the main screen.
Hint: Use a Boolean
variable with shared.Pref.getBoolean
and the key "example_switch"
.
Challenge 2: The DroidCafeWithSettings app displays the settings on a tablet-sized screen properly, but the Up button in the app bar doesn't return the user to the MainActivity as it does on a smartphone-sized screen. This is due to the onOptionsItemSelected()
method in each fragment in SettingsActivity. It uses the following to restart the SettingsActivity when the user taps the Up button:
startActivity(new Intent(getActivity(), SettingsActivity.class));
The above is the appropriate action on smartphone screens in which Settings headers (General, Notifications, and Account) appear in a separate screen. After changing a setting, you want the user's tap on the Up button to take them back to the Settings headers.
However, on a tablet, the headers are always visible in the left pane (while the settings are in the right pane). As a result, tapping the Up button doesn't take the user to MainActivity.
Find a way to make the Up button work properly in SettingsActivity on tablet-sized screens.
Hint: There are several ways to fix this problem. Consider the following:
- You can use multiple
dimens.xml
files in your app to accommodate different screen sizes. When the app runs on a specific device, the appropriatedimens.xml
file is chosen based on the qualifiers for thedimens.xml
files. For example, the app already has adimens.xml (w820dp)
file in the res > values directory, using the(w820dp)
qualifier to specify a device with an 820dp screen width or larger. You can add anotherdimens.xml
file with theLarge
qualifier to specify any device with a large screen, such as a tablet. The app also includes adimens.xml
file in the res > values directory for all other devices, such as smartphones. - You can add the following
bool
resource between the<resources>
and</resources>
tags in thedimens.xml (large)
file, which is automatically chosen for tablets:<resources> <bool name="isTablet">true</bool> </resources>
- You can add the following
bool
resource to thedimens.xml
file, which is chosen when the app runs on any device that is not large:<bool name="isTablet">false</bool>
- Now you can add an if-else block to the
onOptionsItemSelected()
method in each fragment in SettingsActivity that checks to see ifisTablet
is true. If it is, your code can redirect the Up button action to MainActivity.
Summary
In this practical you learned to:
- Add a toggle switch setting (
SwitchPreference
) with attributes in a preference XML file, and set its attributes:android:defaultValue
: The setting default value.android:title
: The setting title.android:key
: The setting key.android:summary
: The setting summary.
- Add a settings activity to view settings, and a fragment that extends
PreferenceFragment
for each specific setting.- Use
getFragmentManager()
to add the fragment to the settings activity - Use
addPreferencesFromResource()
in each fragment to load the appropriate preferences XML file for that fragment.
- Use
- Use an
intent
to connect the Settings item in the options menu to the settings activity. - Set the default values for settings using
PreferenceManager.setDefaultValues()
. - Read the settings values from SharedPreferences using
PreferenceManager.getDefaultSharedPreferences()
, and obtain each setting value using.getString
,.getBoolean
, etc.
Related concepts
The related concept documentation is in Android Developer Fundamentals: Concepts.
Learn more
- Android Studio documentation:
- Android API Guide, "Develop" section:
- Material Design Specification:
- Settings (design)
- Other:
- Stack Overflow: How does one get dimens.xml into Android Studio?
- Stack Overflow: Determine if the device is a smartphone or tablet?