Tuesday, October 18, 2011

Android: How The Preference Framework Works

Every good application needs preferences that enables the user to customize and personalize it to his needs.
Android provides us with a preference framework ready to use. Like the rest of the UI, you have the choice to define your preference declaratively or programmatically. Android stores the preferences as key-value pairs of primitive data types in a shared preferences object.



Example
We will develope a preference activity consisting of two categories, each with a preference in it. The first categorie is defined declarativeley in an XML document while the second is defined programmatically.

The declarative Way of creating preferences
Start a new Android project like I described it in Part0-2 of my 'Getting Started With Android' tutorial.

At first we have to layout the preference screen through an xml file. This file comes by convention in the folder res/xml that we have to create.

Create a new 'Android XML File' from the context menue of the folder. When the dialog pops up, select the resource type 'Preferences', name it my_preferences.xml and choose PreferenceScreen as the root element.

 <?xml version="1.0" encoding="utf-8"?>  
 <PreferenceScreen  
      xmlns:android="http://schemas.android.com/apk/res/android">  
 </PreferenceScreen>  

The preferences UI consists of three basic class types.
PreferenceScreen
It is a container type. It can hold childs of the type PreferenceCategory, Preference and even PreferenceScreen itself to build up a nested preference UI.
PreferenceCategory
Groups Preferences together under one common title.
Preference
The actual preference that is a build in (EditTextPreference, CheckBoxPreference, ...) or custom preference.

 <?xml version="1.0" encoding="utf-8"?>  
 <PreferenceScreen  
      xmlns:android="http://schemas.android.com/apk/res/android"  
      android:key="prefscreen">  
   <PreferenceCategory   
        android:title="category 1"   
        android:key="@string/pref_cat_1_key">  
     <EditTextPreference   
          android:key="@string/pref_edittextpreference_key"   
          android:title="EditTextPreference"   
          android:dialogTitle="EditTextPreference"   
          android:dialogMessage="message"   
          android:summary="summary"/>  
   </PreferenceCategory>  
 </PreferenceScreen>  

For the sake of getting things done quick in tutorials I used plain strings and not the string.xml from the resources.
To bring the my_preferences.xml to the screen, extend an Activity from the class PreferenceActivity. In the onCreate() methode, inflate the ui from the file.

 public class MyPreferenceActivity extends PreferenceActivity {  
      @Override  
      protected void onCreate(Bundle savedInstanceState) {  
           super.onCreate(savedInstanceState);  
           addPreferencesFromResource(R.xml.my_preferences);  
           EditTextPreference etpUsername = (EditTextPreference)
                      findPreference(getString(R.string.pref_edittextpreference_key));  
      }  
 }  

Dont't forget to add the Activity via the AndroidManifest.xml otherwise the app will crash when it can't find it.

 <activity   
      android:name=".MyPreferenceActivity"   
      android:label="Preferences">  
 </activity>  

Now we have to implement the code that opens the MyPreferenceActivity from the options menue.
Create a new menu file 'my_menu.xml' in the folder res/menu.

 <?xml version="1.0" encoding="utf-8"?>  
 <menu  
  xmlns:android="http://schemas.android.com/apk/res/android">  
   <item android:title="@string/menu_item_preferences"   
        android:id="@+id/menu_preferences"   
        android:icon="@android:drawable/ic_menu_preferences"/>  
 </menu>  

In the main Activity we override the following callback methods.

 @Override  
   public boolean onCreateOptionsMenu(Menu menu) {  
        super.onCreateOptionsMenu(menu);  
        MenuInflater mi = getMenuInflater();  
        mi.inflate(R.menu.my_menu, menu);  
        return true;  
   }  
   @Override  
   public boolean onMenuItemSelected(int featureId, MenuItem item) {  
        switch(item.getItemId()) {  
             case R.id.menu_preferences:  
                  Intent i = new Intent(this, MyPreferenceActivity.class);  
                  startActivity(i);  
                  return true;  
        }  
        return super.onMenuItemSelected(featureId, item);  
   }  

Start your Application and have a look at our new preferences screen with the first category.

The programmatic Way of creating preferences
Go back to the MyPreferenceActivity and add the following lines at the end of the onCreate() methode.
They will add a second PreferencCategory called 'category 2' with a CheckBoxPreference in it.

     protected void onCreate(Bundle savedInstanceState) {  
         ...  
         PreferenceManager preferenceManager = getPreferenceManager();  
         PreferenceScreen preferenceScreen = 
                  (PreferenceScreen) preferenceManager.findPreference("prefscreen");  
         PreferenceCategory prefCat2 = new PreferenceCategory(this);  
         prefCat2.setTitle("category 2");  
         preferenceScreen.addPreference(prefCat2);  
         CheckBoxPreference checkBoxPreference = new CheckBoxPreference(this);  
         checkBoxPreference.setTitle("CheckBoxPreference");  
         checkBoxPreference.setSummary("summary");  
         prefCat2.addPreference(checkBoxPreference);  
     }  

With the help of the PreferenceManager we can obtain any preference that is declared so far. We fetch the PreferenceScreen because we want to add another PreferenceCategory at the end. To create an object of one of the preference types, just call the constructor of its class.
Plugging together the hierachy is done with the addPreference() method.

Start your Application and have a look at our new preferences screen.

No comments:

Post a Comment