android - Settings

Applications often include settings that allow users to modify app features and behaviors. For example, some apps allow users to specify whether notifications are enabled or specify how often the application syncs data with the cloud.

Settings Design

For information about how to design your settings, read theSettings design guide.

Because your app's settings UI is built using Preference objects instead of View objects, you need to use a specialized Activity or Fragment subclass to display the list settings:

  • If your app supports versions of Android older than 3.0 (API level 10 and lower), you must build the activity as an extension of the PreferenceActivity class.
  • On Android 3.0 and later, you should instead use a traditional Activity that hosts a PreferenceFragmentthat displays your app settings. However, you can also use PreferenceActivity to create a two-pane layout for large screens when you have multiple groups of settings.
A few of the most common preferences are:CheckBoxPreferenceListPreferenceEditTextPreference
The root node for the XML file must be a  <PreferenceScreen>  element. Within this element is where you add each  Preference . Each child you add within the  <PreferenceScreen>  element appears as a single item in the list of settings.

For example:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <CheckBoxPreference
        android:key="pref_sync"
        android:title="@string/pref_sync"
        android:summary="@string/pref_sync_summ"
        android:defaultValue="true" />
    <ListPreference
        android:dependency="pref_sync"
        android:key="pref_syncConnectionType"
        android:title="@string/pref_syncConnectionType"
        android:dialogTitle="@string/pref_syncConnectionType"
        android:entries="@array/pref_syncConnectionTypes_entries"
        android:entryValues="@array/pref_syncConnectionTypes_values"
        android:defaultValue="@string/pref_syncConnectionTypes_default" />
</PreferenceScreen>

》If you want to provide dividers with headings between groups of settings (as shown in figure 2), place each group of Preference objects inside a PreferenceCategory.

For example:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory 
        android:title="@string/pref_sms_storage_title"
        android:key="pref_key_storage_settings">
        <CheckBoxPreference
            android:key="pref_key_auto_delete"
            android:summary="@string/pref_summary_auto_delete"
            android:title="@string/pref_title_auto_delete"
            android:defaultValue="false"... />
        <Preference 
            android:key="pref_key_sms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_sms_delete"... />
        <Preference 
            android:key="pref_key_mms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_mms_delete" ... />
    </PreferenceCategory>
    ...
</PreferenceScreen>
Using subscreens

If you want to place groups of settings into a subscreen (as shown in figure 3), place the group of Preferenceobjects inside a PreferenceScreen.

<PreferenceScreen  xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- opens a subscreen of settings -->
    <PreferenceScreen
        android:key="button_voicemail_category_key"
        android:title="@string/voicemail"
        android:persistent="false">
        <ListPreference
            android:key="button_voicemail_provider_key"
            android:title="@string/voicemail_provider" ... />
        <!-- opens another nested subscreen -->
        <PreferenceScreen
            android:key="button_voicemail_setting_key"
            android:title="@string/voicemail_settings"
            android:persistent="false">
            ...
        </PreferenceScreen>
        <RingtonePreference
            android:key="button_voicemail_ringtone_key"
            android:title="@string/voicemail_ringtone_title"
            android:ringtoneType="notification" ... />
        ...
    </PreferenceScreen>
    ...
</PreferenceScreen>
In some cases, you might want a preference item to open a different activity instead of a settings screen, such as a web browser to view a web page. To invoke an  Intent  when the user selects a preference item, add an <intent>  element as a child of the corresponding  <Preference>  element.

For example, here's how you can use a preference item to open a web page:

<Preference android:title="@string/prefs_web_page" >
    <intent android:action="android.intent.action.VIEW"
            android:data="http://www.example.com" />
</Preference>
Note: If you're developing your application for Android 3.0 and higher, you should instead usePreferenceFragment. Go to the next section about Using Preference Fragments.
public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}
If you're developing for Android 3.0 (API level 11) and higher, you should use a  PreferenceFragment  to display your list of  Preference  objects. You can add a  PreferenceFragment  to any activity—you don't need to use PreferenceActivity .

Even if your application supports versions of Android older than 3.0, you can build your application to usePreferenceFragment for a two-pane presentation on newer devices while still supporting a traditional multi-screen hierarchy on older devices (see the section about Supporting older versions with preference headers).

public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String settings = getArguments().getString("settings");
        if ("notifications".equals(settings)) {
            addPreferencesFromResource(R.xml.settings_wifi);
        } else if ("sync".equals(settings)) {
            addPreferencesFromResource(R.xml.settings_sync);
        }
    }
}
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <Preference 
        android:title="@string/prefs_category_one"
        android:summary="@string/prefs_summ_category_one"  >
        <intent 
            android:targetPackage="com.example.prefs"
            android:targetClass="com.example.prefs.SettingsActivity"
            android:action="com.example.prefs.PREFS_ONE" />
    </Preference>
    <Preference 
        android:title="@string/prefs_category_two"
        android:summary="@string/prefs_summ_category_two" >
        <intent 
            android:targetPackage="com.example.prefs"
            android:targetClass="com.example.prefs.SettingsActivity"
            android:action="com.example.prefs.PREFS_TWO" />
    </Preference>
</PreferenceScreen>
There are several reasons you might want to be notified as soon as the user changes one of the preferences. In order to receive a callback when a change happens to any one of the preferences, implement the SharedPreference.OnSharedPreferenceChangeListener  interface and register the listener for the SharedPreferences  object by calling  registerOnSharedPreferenceChangeListener() .

The interface has only one callback method, onSharedPreferenceChanged(), and you might find it easiest to implement the interface as a part of your activity. For example:

public class SettingsActivity extends PreferenceActivity
                              implements OnSharedPreferenceChangeListener {
    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
    ...

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
        String key) {
        if (key.equals(KEY_PREF_SYNC_CONN)) {
            Preference connectionPref = findPreference(key);
            // Set summary to be the user-description for the selected value
            connectionPref.setSummary(sharedPreferences.getString(key, ""));
        }
    }
}

@Override
protected void onResume() {
    super.onResume();
    getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
}

@Override
protected void onPause() {
    super.onPause();
    getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
}

Instead, store a reference to the listener in an instance data field of an object that will exist as long as the listener is needed:

SharedPreferences.OnSharedPreferenceChangeListener listener =
    new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // listener implementation
  }
};
prefs.registerOnSharedPreferenceChangeListener(listener);
Once you've added the necessary preferences in your  PreferenceActivity  to control your app's data habits, you should add an intent filter for  ACTION_MANAGE_NETWORK_USAGE  in your manifest file. For example:
<activity android:name="SettingsActivity" ... >
    <intent-filter>
       <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
       <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

This intent filter indicates to the system that this is the activity that controls your application's data usage. Thus, when the user inspects how much data your app is using from the system's Settings app, a View application settings button is available that launches your PreferenceActivity so the user can refine how much data your app uses.

In such a case, you’ll need to create a custom preference by extending the Preference class or one of the other subclasses.

When you extend the Preference class, there are a few important things you need to do:

  • Specify the user interface that appears when the user selects the settings.
  • Save the setting's value when appropriate.
  • Initialize the Preference with the current (or default) value when it comes into view.
  • Provide the default value when requested by the system.
  • If the Preference provides its own UI (such as a dialog), save and restore the state to handle lifecycle changes (such as when the user rotates the screen).

>To properly save and restore the state of your Preference class, you must implement the lifecycle callback methods onSaveInstanceState()and onRestoreInstanceState().

To define how your Preference class saves its state, you should extend the Preference.BaseSavedStateclass. You need to override just a few methods and define the CREATOR object.

For most apps, you can copy the following implementation and simply change the lines that handle the value if your Preference subclass saves a data type other than an integer.

private static class SavedState extends BaseSavedState {
    // Member that holds the setting's value
    // Change this data type to match the type saved by your Preference
    int value;

    public SavedState(Parcelable superState) {
        super(superState);
    }

    public SavedState(Parcel source) {
        super(source);
        // Get the current preference's value
        value = source.readInt();  // Change this to read the appropriate data type
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        // Write the preference's value
        dest.writeInt(value);  // Change this to write the appropriate data type
    }

    // Standard creator object using an instance of this class
    public static final Parcelable.Creator<SavedState> CREATOR =
            new Parcelable.Creator<SavedState>() {

        public SavedState createFromParcel(Parcel in) {
            return new SavedState(in);
        }

        public SavedState[] newArray(int size) {
            return new SavedState[size];
        }
    };
}

With the above implementation of Preference.BaseSavedState added to your app (usually as a subclass of your Preference subclass), you then need to implement the onSaveInstanceState() andonRestoreInstanceState() methods for your Preference subclass.

For example:

@Override
protected Parcelable onSaveInstanceState() {
    final Parcelable superState = super.onSaveInstanceState();
    // Check whether this Preference is persistent (continually saved)
    if (isPersistent()) {
        // No need to save instance state since it's persistent,
        // use superclass state
        return superState;
    }

    // Create instance of custom BaseSavedState
    final SavedState myState = new SavedState(superState);
    // Set the state's value with the class member that holds current
    // setting value
    myState.value = mNewValue;
    return myState;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    // Check whether we saved the state in onSaveInstanceState
    if (state == null || !state.getClass().equals(SavedState.class)) {
        // Didn't save the state, so call superclass
        super.onRestoreInstanceState(state);
        return;
    }

    // Cast state to custom BaseSavedState and pass to superclass
    SavedState myState = (SavedState) state;
    super.onRestoreInstanceState(myState.getSuperState());
    
    // Set this Preference's widget to reflect the restored state
    mNumberPicker.setValue(myState.value);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值