1. Welcome
Introduction
Apps often include settings that allow users to modify app features and behaviors. For example, some apps allow the user to set their home location, default units for measurements, and other settings that apply to the entire app. Users don't access settings frequently, 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 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
You should be able to:
- Create an Android Studio project from a template and generate the main layout.
- Run apps on the emulator or a connected device.
- Create and edit UI elements using the layout editor and XML code.
- Extract string resources and edit string values.
- Access UI elements from your code using
findViewById()
. - Handle a
Button
click. - Display a
Toast
message. - Add an
Activity
to an app. - Create an options menu in the app bar.
- Add and edit the menu items in the options menu.
- Use styles and themes in a project.
- Use
SharedPreferences
.
What you'll learn
- How to add a
Fragment
for managing settings. - How to create an XML resource file of settings with their attributes.
- How to create navigation to the settings
Activity
. - How to set the default values of settings.
- How to read the settings values changed by the user.
- How to customize the Settings Activity template.
What you'll do
- Create an app that includes Settings in the options menu.
- Add a Settings option 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.
2. App overview
Android Studio provides a shortcut for setting up an options menu with Settings. If you start an Android Studio project for a phone 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 you'll 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 DroidCafeOptionsUp 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 phones and tablets:
- Phones: 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.
To customize the template, you'll change the headers, setting titles, setting descriptions, and values for the settings.
The DroidCafeOptionsUp 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.
3. Task 1: Add a switch setting to an app
In this task, you do the following:
- Create a new project based on the Basic Activity template, which provides an options menu.
- Add a toggle switch (
SwitchPreference
) with attributes in a preference XML file. - Add an activity for settings and a fragment for a specific setting. To maintain compatibility with
AppCompatActivity
, you usePreferenceFragmentCompat
rather thanPreferenceFragment
. You also add theandroid.support.v7.preference
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) |
Project location | Path to your directory of projects |
Phone and Tablet Minimum SDK | API15: Android 4.0.3 IceCreamSandwich |
Template | Basic Activity |
Activity Name | MainActivity |
Layout Name | activity_main |
Title | MainActivity |
- 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.
- You need to create a new resource directory to hold the XML file containing the settings. Select the res directory in the Project > Android pane, 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
folder appears in the Project > Android pane inside theres
folder. Select xml and choose File > New > XML resource file (or right-click xml 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 thexml
folder, and the layout editor appears, as shown in the figure below.
In the figure above:
- The
preferences.xml
file inside thexml
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 Attributes pane on the right side of the layout editor as follows, and as shown in 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 see the XML code:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="true"
android:key="example_switch"
android:summary="Turn this option on or off"
android:title="Settings option" />
</PreferenceScreen>
- Extract the string resources for the
android:title
andandroid:summary
attribute values to@string/switch_title
and@string/switch_summary
.
The XML attributes for a preferences are:
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 defaultSharedPreferences
file for your app's settings.android:summary
: The text summary appears underneath the setting.
1.3 Use SwitchPreferenceCompat
In order to use the PreferenceFragmentCompat
version of PreferenceFragment
, you must also use the android.support.v7
version of SwitchPreference
(SwitchPreferenceCompat
).
- In the Project > Android pane, open the build.gradle (Module: app) file in the Gradle Scripts folder, and add the following to the
dependencies
section:
implementation 'com.android.support:preference-v7:26.1.0'
The statement shown above adds the android.support.v7.preference
library in order to use the PreferenceFragmentCompat
version of PreferenceFragment
.
- In the preferences.xml file in the xml folder, change
<SwitchPreference
in the code to<android.support.v7.preference.SwitchPreferenceCompat
:
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="example_switch"
android:summary="@string/switch_summary"
android:title="@string/switch_title" />
The SwitchPreferenceCompat
line above may show a yellow light bulb icon with a warning, but you can ignore it for now.
- Open the styles.xml file in the values folder, and add the following
preferenceTheme
item to theAppTheme
declaration:
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
In order to use PreferenceFragmentCompat
, you must also declare preferenceTheme
with the PreferenceThemeOverlay
style to the app theme.
1.4 Add an Activity for settings
In order to create a settings Activity
that provides a UI for settings, add an Empty Activity to the app. Follow these steps:
- Select app at the top of the Project > Android pane, and choose New > Activity > Empty Activity.
- Name the
Activity
SettingsActivity. Uncheck the Generate Layout File option (you don't need one), and leave unchecked the Launcher Activity option. - Leave the Backwards Compatibility (AppCompat) option checked. The Package name should already be set to com.example.android.projectname**.
- Click Finish.
1.5 Add a Fragment for a specific setting
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. 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. PreferenceFragment
provides a more flexible architecture for your app, compared to using an Activity
for the preferences.
You will use PreferenceFragmentCompat
rather than PreferenceFragment
in order to maintain compatibility with AppCompatActivity
.
In this step you will add a blank Fragment
for a group of similar settings (without a layout, factory methods, or interface callbacks) to the app, and extend PreferenceFragmentCompat
.
Follow these steps:
- Select app again, and choose New > Fragment > Fragment (Blank).
- Name the fragment SettingsFragment. Uncheck the Create layout XML? option (you don't need one).
- Uncheck the options to include fragment factory methods and interface callbacks.
- The Target Source Set should be set to main.
- 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;
}
}
- Edit the class definition of
SettingsFragment
to extendPreferenceFragmentCompat
:
public class SettingsFragment extends PreferenceFragmentCompat {
As you change the class definition so it matches the definition shown above, a red bulb appears in the left margin. Click the red bulb and choose Implement methods, and then choose onCreatePreferences. Android Studio creates the following onCreatePreferences()
stub:
@Override
public void onCreatePreferences(Bundle
savedInstanceState, String rootKey) {
}
In order to extend the Fragment
, Android Studio adds the following import statement:
import android.support.v7.preference.PreferenceFragmentCompat;
- Delete the entire
onCreateView()
method in the fragment.
The reason why you are essentially replacing onCreateView()
with onCreatePreferences()
is because you will be adding this SettingsFragment
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
using rootKey
.
You can safely delete the empty constructor from SettingsFragment
as well, because the Fragment
is not displayed by itself:
public SettingsFragment() {
// Required empty public constructor
}
- You need to associate with this
Fragment
thepreferences.xml
settings resource you created in a previous step. Add to the newly createdonCreatePreferences()
stub a call tosetPreferencesFromResource()
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);
}
1.6 Display the Fragment in SettingsActivity
To display the Fragment
in SettingsActivity
, follow these steps:
- Open SettingsActivity.
- Add the following code to the end of the
onCreate()
method so that theFragment
is displayed as the main content:
getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
The code above uses the typical pattern for adding a fragment to an activity so that the fragment appears as the main content of the activity:
- Use
getFragmentManager()
if the class extendsActivity
and theFragment
extendsPreferenceFragment
. - Use
getSupportFragmentManager()
if the class extendsAppCompatActivity
and theFragment
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.7 Connect the Settings menu item to SettingsActivity
Use an Intent
to launch SettingsActivity
from MainActivity
when the user selects Settings from the options menu.
- Open MainActivity and find the
if
block in theonOptionsItemSelected()
method, 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 launchSettingsActivity
:
if (id == R.id.action_settings) {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
- To add the app bar Up navigation button to
SettingsActivity
, you need to edit its declaration in theAndroidManifest.xml
file to define theSettingsActivity
parent
asMainActivity
. Open AndroidManifest.xml and find theSettingsActivity
declaration:
<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>
- Run the app. Tap the overflow icon for the options menu, as shown on the left side of the figure below. 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.8 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:
- Open MainActivity.
- Add the following to the end of the
onCreate()
method after theFloatingActionButton
code:
android.support.v7.preference.PreferenceManager
.setDefaultValues(this, R.xml.preferences, false);
The code above ensures that the settings are properly initialized with their default values. The PreferenceManager.setDefaultValues()
method takes three arguments:
- The app
context
, such asthis
. - 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. Whenfalse
, the system sets the default values only if this method has never been called. As long as you set this third argument tofalse
, you can safely call this method every timeMainActivity
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.9 Read the changed settings value from shared preferences
When the app starts, the MainActivity
onCreate()
method can read the 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 using PreferenceManager.getDefaultSharedPreferences()
.
Follow these steps to add that code:
- Open SettingsActivity and create a
static
String
variable to hold the key for the value:
public static final String
KEY_PREF_EXAMPLE_SWITCH = "example_switch";
- Open MainActivity and add the following at end of the
onCreate()
method:
SharedPreferences sharedPref =
android.support.v7.preference.PreferenceManager
.getDefaultSharedPreferences(this);
Boolean switchPref = sharedPref.getBoolean
(SettingsActivity.KEY_PREF_EXAMPLE_SWITCH, false);
Toast.makeText(this, switchPref.toString(),
Toast.LENGTH_SHORT).show();
- Run the app and 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 toMainActivity
. TheToast
message should appear inMainActivity
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.
The code snippet shown above uses the following:
android.support.v7.preference.PreferenceManager.getDefaultSharedPreferences(this)
to get the setting as aSharedPreferences
object (sharedPref
).getBoolean()
to get theBoolean
value of the setting that uses the key (KEY_PREF_EXAMPLE_SWITCH
defined inSettingsActivity
) 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.Toast.makeText()
andshow()
to display the value of theswitchPref
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.
Task 1 solution code
Android Studio project: AppWithSettings
4. Task 2: Use 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 DroidCafeOptionsUp using the Basic Activity template, which provides an options menu in the app bar as shown below.
Legend for the figure above:
- App bar
- Options menu action icons
- Overflow button
- Options overflow menu
2.1 Explore the Settings Activity template
To include the Settings Activity template in an app project in Android Studio, follow these steps:
- Copy the DroidCafeOptionsUp project folder, and rename it to DroidCafeWithSettings. Run the app to make sure it runs properly.
- Select app at the top of the Project > Android pane, 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 menu, and click the Project tab in the Select Activity dialog that appears (refer to the figure below).
- Expand DroidCafeWithSettings > app > src > main > java > com.example.android.droidcafeinput and select MainActivity as the parent activity, as shown in the figure below. Click OK.
You choose MainActivity
as the parent so that the Up app bar 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.
- In the Project > Android pane, expand the app > res > xml folder to see the XML files created by the Settings Activity template.
You can open and then add to or customize the XML files 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
, 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 option that can be toggled (such as on/off or true/false).EditTextPreference
: A dialog with anEditText
.RingtonePreference
: A dialog with ringtones on the device.
The Settings Activity template also creates:
SettingsActivity
in thejava/com.example.android.
projectname
folder, 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 thejava/com.example.android.
projectname
folder, which you use as is. ThisActivity
is a helper class thatSettingsActivity
uses to maintain backward compatibility with previous versions of Android.
2.2 Add the Settings menu item and connect it to the activity
As you learned in another practical, you can edit the menu_main.xml
file for the options menu to add or remove menu items.
- Expand the res folder in the Project > Android pane, and open menu_main.xml file. Click the Text tab to show the XML code.
- 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" />
You specify "never"
for the app:showAsAction
attribute so that Settings appears only in the overflow options menu and not in the app bar itself, because it should not be used often. You specify "50"
for the android:orderInCategory
attribute so that Settings appears below Favorites (set to "30"
) but above Contact (set to "100"
).
- Extract the string resource for
"Settings"
in theandroid:title
attribute to the resource namesettings
. - Open MainActivity, and find the
switch case
block in theonOptionsItemSelected()
method which handles the tap on items in the options menu. Shown below is a snippet of that method showing the firstcase
(foraction_order
):
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_order:
Intent intent = new Intent(MainActivity.this,
OrderActivity.class);
intent.putExtra(EXTRA_MESSAGE, mOrderMessage);
startActivity(intent);
return true;
case R.id.action_status:
// Code for action_status and other cases...
}
return super.onOptionsItemSelected(item);
}
- Note in the above code that the first
case
uses anIntent
to launchOrderActivity
. Add a newcase
foraction_settings
to theswitch case
block with similarIntent
code to launchSettingsActivity
(but without theintent.putExtra
):
case R.id.action_settings:
Intent settingsIntent = new Intent(this,
SettingsActivity.class);
startActivity(settingsIntent);
return true;
- Run the app using a phone or emulator so that you can see how the Settings Activity template handles the phone screen size.
- 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 toMainActivity
.
You use the Settings Activity template code as-is. It not only provides layouts for phone-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.
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.
- Expand the res > values folder and open the strings.xml file. 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>
<string-array name="list_preference_entries">
<item>Entry 1</item>
<item>Entry 2</item>
<item>Entry 3</item>
</string-array>
<string-array name="list_preference_entry_values">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="multi_select_list_preference_default_value" />
<string name="pref_title_system_sync_settings">System sync settings</string>
- 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). - You should now refactor the resource name (the app will still work without refactoring the name, but refactoring makes the code easier to understand). Right-click (or Control-click) the pref_header_data_sync resource name choose Refactor > Rename. Change the name to pref_header_account, click the option to search in comments and strings, and click Refactor.
- You should also refactor the XML file name (the app will still work without refactoring the name, but refactoring makes the code easier to understand). Right-click (or Control-click) the pref_data_sync resource name in the Project > Android pane, and choose Refactor > Rename. Change the name to pref_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
pref_title_sync_frequency
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 that correspond to the countries above, such as US, CA, etc.:
<string-array name="pref_market_values">
<item>US</item>
<item>CA</item>
<item>UK</item>
<item>IN</item>
<item>JA0</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_account.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 to "US":
android:defaultValue="US"
Because the key for this setting preference ("sync_frequency"
) is hard-coded elsewhere in the Java code, don't change the android:key
attribute. Instead, keep using "sync_frequency"
as the key for this setting in this example. If you were thoroughly customizing the settings for a real-world app, you would take the time to change the hard-coded keys throughout the code.
2.4 Add code to set the default values for the settings
To add code to set the default values for the settings, follow these steps:
- Open MainActivity and find the
onCreate()
method. - Add the following
PreferenceManager.setDefaultValues
statements at the end of theonCreate()
method:
PreferenceManager.setDefaultValues(this,
R.xml.pref_general, false);
PreferenceManager.setDefaultValues(this,
R.xml.pref_notification, false);
PreferenceManager.setDefaultValues(this,
R.xml.pref_account, false);
The default values are already specified in the XML file with the android:defaultValue
attribute, but the above statements ensure that the SharedPreferences
file is properly initialized with the default values. The setDefaultValues()
method takes three arguments:
- The app
context
, such asthis
. - 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. Whenfalse
, the system sets the default values only when this method is called for the first time. As long as you set this third argument tofalse
, you can safely call this method every time yourActivity
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");
displayToast(marketPref);
As you learned in the previous task, you use PreferenceManager.getDefaultSharedPreferences(this)
to get the setting as a SharedPreferences
object (marketPref
). You then use getString()
to get the string value of the setting that uses the key (sync_frequency
), and assign it to marketPref
. If there is no value for the key, the getString()
method assigns the setting value of marketPref
to -1
, which is the value of Other
in the pref_market_values
array.
- Run the app. 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 app, you should see "-1" displayed in theToast
because you haven't changed the setting yet. - Tap Settings in the options menu, and tap Account in the Settings screen. Tap Market, and choose Canada 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.
- Run the app again from Android Studio. You should see a
Toast
message with "CA" (for Canada), and the Market setting is now set to Canada.
You have successfully integrated the Settings Activity with the 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.
Task 2 solution code
Android Studio project: DroidCafeWithSettings
5. Coding challenge
Challenge: 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 phone-sized screen. This is due to the three onOptionsItemSelected()
methods—one for 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 phone screens in which Settings headers (General, Notifications, and Account) appear in a separate screen (SettingsActivity
). After changing a setting, you want the user's tap on the Up button to take the user back to the Settings headers in SettingsActivity
. A further tap on Up takes the user back to MainActivity
.
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: While there are several ways to fix this problem, consider the following steps:
- Add another
dimens.xml
file to specifically accommodate screen sizes larger than 600dp. When the app runs on a specific device, the appropriatedimens.xml
file is chosen based on the qualifiers for thedimens.xml
files. You can add anotherdimens.xml
file with the Smallest Screen Width qualifier set to 600 dp (sw600dp
), as you learned in the practical on supporting landscape and screen sizes, to specify any device with a large screen, such as a tablet. - Add the following
bool
resource between the<resources>
and</resources>
tags in thedimens.xml (sw600dp)
file, which is automatically chosen for tablets:
<bool name="isTablet">true</bool>
- Add the following
bool
resource to the standarddimens.xml
file, which is chosen when the app runs on any device that is not large:
<bool name="isTablet">false</bool>
- In
SettingsActivity
, you can add to all threeonOptionsItemSelected()
methods (one for eachFragment
) anif else
block that checks to see ifisTablet
is true. If it is, your code can redirect the Up button action toMainActivity
.
6. Challenge solution code
Android Studio project: DroidCafeWithSettingsChallenge
7. Summary
Users expect to navigate to app settings by tapping Settings in side navigation, such as a navigation drawer, or in the options menu in the app bar.
To provide user settings for your app, provide an Activity
for settings:
- Use an
Activity
that hosts aPreferenceFragment
to display the app settings. - To maintain compatibility with
AppCompatActivity
and theandroid.support.v7.preference library
, usePreferenceFragmentCompat
rather thanPreferenceFragment
.
Show each fragment in the settings activity:
- If the activity class extends
Activity
and the fragment class extendsPreferenceFragment
, usegetFragmentManager()
. - If the activity class extends
AppCompatActivity
and the fragment class extendsPreferenceFragmentCompat
, usegetSupportFragmentManager()
. - To associate the
preferences.xml
settings resource with the fragment, usesetPreferencesFromResource()
. - To set the default values for settings, use
PreferenceManager.setDefaultValues()
. - To connect the Settings menu item to the settings activity, use an
Intent
.
Add XML resource files for the settings:
- Create a new resource directory (File > New > Android Resource Directory).
- In the Resource type drop-down menu, select xml. The
xml
folder appears inside theres
folder. - Click on xml and select File > New > XML resource file.
- Enter preferences as the name of the XML file. The
preferences.xml
file appears inside thexml
folder.
Add UI controls such as toggle switches, with attributes in a preferences XML file:
- To maintain compatibility with
AppCompatActivity
, use theandroid.support.v7.preference library
version. For example, useSwitchPreferenceCompat
for toggle switches.
Use attributes with each UI element for settings:
android:defaultValue
is the value of the setting when the app starts for the first time.android:title
is the user-visible setting title.android:key
is the key used for storing the setting value.android:summary
is the user-visible text that appears under the setting.
Save and read settings values:
- When the app starts, the
MainActivity
onCreate()
method can read the 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 theSharedPreferences
file. - To use the value of the setting, your app can use the key to get the setting from the
SharedPreferences
file. - Your app reads settings values from
SharedPreferences
usingPreferenceManager.getDefaultSharedPreferences()
, and obtains each setting value using.getString
,.getBoolean
, etc.
8. Related concepts
The related concept documentation is in 9.2: App settings.
9. Learn more
Android Studio documentation: Android Studio User Guide
Android developer documentation:
- Settings (overview)
Preference
PreferenceFragment
PreferenceFragmentCompat
Fragment
SharedPreferences
- Save key-value data
- Support different screen sizes
Material Design specification: Android settings
Stack Overflow:
10. Homework
This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:
- Assign homework if required.
- Communicate to students how to submit homework assignments.
- Grade the homework assignments.
Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.
If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.
Build and run an app
Open the DroidCafeWithSettings app project.
- Add a
ListPreference
(a dialog with radio buttons) to the general settings. Put the dialog in the General settings screen, below the "Add friends to order messages"ListPreference
. - Edit the string arrays used for the
ListPreference
to include the title "Choose a delivery method." Use the same delivery choices that are used in the radio buttons in theOrderActivity
. - Make the user's chosen delivery method appear in the same
Toast
message as the chosen Market setting. - Extra credit: Show the selected delivery method as the setting summary text that appears underneath the
ListPreference
title. Enable this text to change with each update.
Answer these questions
Question 1
In which file of the DroidCafeWithSettings project do you define the array of entries and the array of values for the ListPreference
? Choose one:
pref_general.xml
strings.xml
menu_main.xml
activity_main.xml
content_main.xml
Question 2
In which file of the DroidCafeWithSettings project do you use the array of entries and the array of values in setting up the ListPreference
, and also set the ListPreference
key and default value? Choose one:
pref_general.xml
strings.xml
menu_main.xml
content_main.xml
SettingsActivity.java
Question 3
How do you set up a settings Activity
and a Fragment
with a SwitchPreference
for the UI, and still remain compatible with the v7 appcompat library
for backward compatibility with older versions of Android?
- Use a settings activity that extends
Activity
, a fragment that extendsPreferenceFragment
, and aSwitchPreference
for the UI. - Change
MainActivity
to extendActivity
. - Use a settings activity that extends
AppCompatActivity
, a fragment that extendsPreferenceFragmentCompat
, and aSwitchPreferenceCompat
for the UI. - You can't use a fragment with a
SwitchPreference
and remain compatible with thev7 appcompat library
.
Submit your app for grading
Guidance for graders
Check that the app has the following features:
- The
onCreate()
method reads thedeliveryPref
setting usingsharedPref.getString()
. - The
pref_general.xml
file includes aListPreference
that uses for its entries an array of delivery choices. - Extra credit: The statement
bindPreferenceSummaryToValue(findPreference("delivery"))
has been added to theonCreate()
method of theGeneralPreferenceFragment
class in theSettingsActivity
in order to show the delivery choice in the preference summary.
11. Next codelab
To find the next practical codelab in the Android Developer Fundamentals (V2) course, see Codelabs for Android Developer Fundamentals (V2).
For an overview of the course, including links to the concept chapters, apps, and slides, see Android Developer Fundamentals (Version 2).