Android Core

Android Quick Preferences Tutorial

When developing a mobile application, a common need that arises is the one of storing user’s preferences and using them when the application starts. Since this is a recurring need, Google has created a preferences framework for us. The provided mechanism allows us to show, save and manipulate user’s preferences very easily. Furthermore, the framework has support for automatic UI creation. What I mean is, that, by declaring the type of a user preference, a user interface for manipulating these preferences is automatically generated, without having to write a single line code. How does that sound for rapid application development?

In order to make use of the preferences framework, the first step is to extend the PreferenceActivity class. This is just a convenience class that derives from ListActivity and allows to bootstrap the preferences UI from an XML file. Additionally, it automatically saves to SharedPreferences behind the scenes. Don’t forget that SharedPreferences is the interface responsible for accessing and modifying preference data and that we can manually manipulate it by calling the getSharedPreferences method of an Activity. In order to tie together our PreferenceActivity class and the XML layout file, we use the addPreferencesFromResource method. Thus, our onCreate method is very simple and looks like this:

...
@Override
public void onCreate(Bundle savedInstanceState) {     
    super.onCreate(savedInstanceState);        
    addPreferencesFromResource(R.xml.preferences);        
}
...

This assumes that we have already created a file named “preferences.xml” inside the “res/xml” folder. Then, in run-time, the activity will inflate the given XML resource and add the preference hierarchy to the current preference hierarchy. This XML file has a specific format via which we define the types of the preferences. All types derive from the Preference class, which represents the basic preference UI building block and provides the View to be displayed in the activity and the association with a SharedPreferences object to store/retrieve the preference data. Here are some of the most common subclasses that you can directly use:

  • CheckBoxPreference: Provides checkbox widget functionality. Will store a Boolean value.
  • RingtonePreference: Allows the user to choose a ringtone from those on the device. The chosen ringtone’s URI will be persisted as a string.
  • EditTextPreference: Allows for string input. Will store a string into the SharedPreferences.
  • ListPreference: Displays a list of entries as a dialog. This preference will store a string into the SharedPreferences.

Also bear in mind that various preferences can be grouped into categories by using the PreferenceCategory class, which groups Preference objects and provides a disabled title above the group.

Let’s examine what our XML declaration file will be consisted of. We are going to have two categories. Under the first one, we will have a CheckBoxPreference, which will enable or disable data updates to a hypothetical application and a ListPreference which through which we will define how often we want updates to happen. As you might have guessed, there is a dependency between the two preferences. This can be achieved by using the android:dependency attribute. Finally, under the second category, we will have a EditTextPreference via which a welcome message will be saved and shown when necessary. This is what the XML file looks like:

<?xml version="1.0" encoding="utf-8"?>

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory 
        android:title="First Category"
        android:key="first_category">
        
        <CheckBoxPreference 
            android:key="perform_updates"
            android:summary="Enable or disable data updates"
            android:title="Enable updates" 
            android:defaultValue="true"
        />
        
        <ListPreference 
            android:key="updates_interval"
            android:title="Updates interval"
            android:summary="Define how often updates will be performed"
            android:defaultValue="1000" 
            android:entries="@array/updateInterval"
            android:entryValues="@array/updateIntervalValues"
            android:dependency="perform_updates"
        />    
            
    </PreferenceCategory>

    <PreferenceCategory 
        android:title="Second Category"
        android:key="second_category">

        <EditTextPreference
            android:key="welcome_message"
            android:title="Welcome Message" 
            android:summary="Define the Welcome message to be shown"
            android:dialogTitle="Welcome Message"
            android:dialogMessage="Provide a message"    
            android:defaultValue="Default welcome message" />

    </PreferenceCategory>
    
</PreferenceScreen>

Note that for the ListPreference, an android:entries attribute is defined. We use that to load predefined values which are kept in an external XML file under the name “res/values/arrays.xml”. The “updateInterval” and “updateIntervalValue” entries are used from that file. These are actually key-value pairs, so the actual value stored is the one in the second list. Here is what the file looks like:

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string-array name="updateInterval">
        <item name="1000">Every 1 second</item>
        <item name="5000">Every 5 seconds</item>
        <item name="30000">Every 30 seconds</item>
        <item name="60000">Every 1 minute</item>
        <item name="300000">Every 5 minutes</item>
    </string-array>
    
    <string-array name="updateIntervalValues">
        <item name="1000">1000</item>
        <item name="5000">5000</item>
        <item name="30000">30000</item>
        <item name="60000">60000</item>
        <item name="300000">300000</item>
    </string-array>

</resources>

As we explained, the persisting part of the equation is handled by the framework. In order to show you how to read the already persisted values, we will create another activity which will be launched from our main one. Let’s first see how the main activity looks like:

package com.javacodegeeks.android.preferences;

import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.view.Menu;
import android.view.MenuItem;

public class QuickPrefsActivity extends PreferenceActivity {
    
    @Override
    public void onCreate(Bundle savedInstanceState) {        
        super.onCreate(savedInstanceState);        
        addPreferencesFromResource(R.xml.preferences);        
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(Menu.NONE, 0, 0, "Show current settings");
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case 0:
                startActivity(new Intent(this, ShowSettingsActivity.class));
                return true;
        }
        return false;
    }
    
}

Nothing special here. We just provide an options menu with only one MenuItem by using the onCreateOptionsMenu method. When the user selects the specific item, we handle its actions inside the onOptionsItemSelected method and we launch a new activity using the startActivity method. If you want to learn more about option menus, check out my older tutorial named “Using options menus and customized dialogs for user interaction”. More information about starting activities can be found in my tutorial “Launching new activities with intents”.

Let’s now create the “ShowSettingsActivity”. First, we have to declare it in the Android manifest file, so here what our “AndroidManifest.xml” file looks like:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.javacodegeeks.android.preferences"
      android:versionCode="1"
      android:versionName="1.0">
      
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        
        <activity android:name=".QuickPrefsActivity" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <activity android:name=".ShowSettingsActivity" />
        
    </application>
    
    <uses-sdk android:minSdkVersion="3" />

</manifest> 

Here is the code for the activity itself:

package com.javacodegeeks.android.preferences;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.widget.TextView;

public class ShowSettingsActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);
  setContentView(R.layout.show_settings_layout);

  SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);

  StringBuilder builder = new StringBuilder();

  builder.append("\n" + sharedPrefs.getBoolean("perform_updates", false));
  builder.append("\n" + sharedPrefs.getString("updates_interval", "-1"));
  builder.append("\n" + sharedPrefs.getString("welcome_message", "NULL"));

  TextView settingsTextView = (TextView) findViewById(R.id.settings_text_view);
  settingsTextView.setText(builder.toString());

 }

}

Inside the activity, we take reference of the SharedPreferences class by using the static method getDefaultSharedPreferences of the PreferenceManager class. Then, depending on the data type of the preference, we use the appropriate getter method, such as getBoolean or getString. Note that the second argument to those is a default value which will be used if a a value has not yet been stored. We use as keys those defined in the original “preferences.xml” file, i.e. “perform_updates”, “updates_interval” and “welcome_message”. The values are concatenated and then presented in a TextView.

Here is also the simple layout for the specific activity:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
    <TextView
        android:id="@+id/settings_text_view"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
    />
    
</LinearLayout>

If we now launch the Eclipse configuration, we will get a preferences screen like the following:

preferences screen

Clicking on the “Updates Interval” will cause a list of options to appear:

list preferences

Similarly, clicking on the “Welcome Message” preference will cause an edit text to appear:

edit text preferences

Now let’s read the already persisted values. Hit the “Menu” button on the emulator so that the options menu appears and choose the “Show current settings” item. This will launch our second activity inside which the values are read and presented as follows:

read Preferences

That’s it guys. A quick guide on how to leverage the preferences framework provided in the SDK to rapidly manipulate user preferences in your application. You can find the Eclipse project created in this tutorial here.

Cheers!

Related Articles :
Related Snippets :

Ilias Tsagklis

Ilias is a software developer turned online entrepreneur. He is co-founder and Executive Editor at Java Code Geeks.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

17 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Martin Madsen
Martin Madsen
12 years ago

This is a very nice, simple tutorial that explains all the basics in a simple language and provides good examples. You make it seem so easy! Well, I guess it is. Anyways, loved the tutorial, cheers to you :)

Favas Kv
12 years ago

Nice tutorial, simple, easy to learn…u r great…thank u very much… 

Shabnaz J
Shabnaz J
11 years ago

How to save the dynamiclly created textbox when a button is clicked.. on each button click a textbox will be added.. so I will not know initally how many text box are created. when the activity is destroyed and again launched it should display with the previous state..i.e the same textboxes which i created before.. please help me ..

Srikanth
11 years ago

Very nice yar . such a good example . good explanation .

Steve Watson
Steve Watson
11 years ago

Whilst this is a very useful tutorial, I have never seen such a disorganised piece of text-based learning in my life.  There is information that is in the wrong place, e,g, the first code snippet is followed by: “This assumes that we have already created a file named “preferences.xml” inside the “res/xml” folder.”  This is also followed later by a similar reference to a layout file which is then described after the initial reference.  Whilst I appreciate that you are not necessarily wanting to spoon-feed your visitors you could at least put all of the food on the plate at… Read more »

Peter Smithson
Peter Smithson
11 years ago
Reply to  Steve Watson

That might explain some problems I’m having – it gives bits of XML but doesn’t tell you where to put them – I think I’ll download the source as it might be easier.

J.D. Schuitemaker
J.D. Schuitemaker
11 years ago

Very useful! I am looking for something where I can make the preferences unreadable for those who are going to decompile the APK. do you know if something like that exists? The reason I want that is because I am calling web services that I don’t want to be used by others and I have not yet found a good way to do it in other ways.

Lukasz P
Lukasz P
11 years ago

now it is useless because of “This method is deprecated.
This function is
not relevant for a modern fragment-based PreferenceActivity.

Inflates the given XML resource and adds the preference hierarchy to the
current preference hierarchy.”

Maciej J
11 years ago
Reply to  Lukasz P

It’s not useless, because we are still in API 10 world see:
http://developer.android.com/about/dashboards/index.html

Besides deprecation doesn’t mean it doesn’t work in new versions of API. Furthermore personally I don’t like new fragmented version. It just doesn’t fit in if you need few simple preferences.

Peter_Pedro
Peter_Pedro
11 years ago
Reply to  Maciej J

Agree, I even use API 8 as a minimum. I use deprecated methods all the time :)

Rafał Machnik
11 years ago

Now you can use PreferenceFragment to define preferences in the same way from the xml file. Check it ;)

Caio
Caio
11 years ago

Can I have two quick preferences? and how see each them, such as alarm android for example. Thanks

karim naik
11 years ago

can u tell me how to disable a particular item of list preference?

chf
chf
10 years ago

Thanks for this useful article. It’s missing some pieces but since it’s geared towards Android devs it’s not really an issue. Learning is most effective when figuring things out :)

Felipe
Felipe
10 years ago

Very useful, I appreciate the time spent to develop this tutorial.

andy
andy
10 years ago

This is VERY OUTDATED. Please update with NON depreciated content. This tutorial NO LONGER teaches what it claims. This code WILL NOT WORK PROPERLY.

Marc
Marc
9 years ago
Reply to  andy

Yeah, that’s right. For example, the item tag doesn’t have a name attribute anymore.

Back to top button