PreferenceActivity — Активити с настройками


Практически любое приложение включает в себя экран с настройками, которые обычно сохраняются в Preferences. При этом Андроид-фреймворк предлагает нам очень удобный инструмент по созданию Активити с настройками — PreferenceActivity, где многие рутинные операции выполняются автоматически, а наш код становится при этом более чистым и читабельным. В этой статье мы рассмотрим простейший пример по созданию такого Активити.

PreferenceActivity - Активити с настройками

Создадим приложение, где будет два экрана (Активити). В первом — MainActivity будет простой layout с двумя кнопками: «К настройкам» и «Получить настройки». При нажатии на первую мы будем переходить на Активити с настройками, а при клике на вторую — выводить сохраненные настройки в логи.

В Активити с настройками у нас будет две секции.

- Общие настройки с одним чекбоксом
- Другие настройки, где две «настройки» — логин и частота уведомлений. При редактировании первой будет открываться диалог с EditText, а при редактировании второй — диалог с переключателями для выбора только одного значения.

Добавим строковые ресурсы.

res/values/strings.xml

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

    <string name="app_name">PreferenceActivity</string>
    <string name="action_settings">Settings</string>
    <string name="to_settings">К настройкам</string>
    <string name="get_settings">Получить настройки</string>

</resources>

Строковые ресурсы для настроек вынесем в отдельный файл res/values/strings_settings.xml

<resources>
    <string name="title_activity_settings">Settings</string>
    <string name="pref_header_general">Общие настройки</string>
    <string name="pref_header_other_general">Другие настройки</string>
    <string name="check_news">Проверять обновления</string>
    <string name="check_news_description">Проверка будет проходить в фоновом режиме</string>
    <string name="pref_title_login">Логин пользователя</string>
    <string name="pref_default_login">yourlogin</string>
    <string name="pref_title_notifications">Частота уведомлений</string>
    <string-array name="pref_list_titles">
        <item>Всегда</item>
        <item>По событию</item>
        <item>Никогда</item>
    </string-array>
    <string-array name="pref_list_values">
        <item>1</item>
        <item>0</item>
        <item>-1</item>
    </string-array>
</resources>

Создадим описание для экрана с настройками (его элементы) — res/xml/pref_general.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory
        android:title="@string/pref_header_general"
        android:key="pref_key_settings">

        <CheckBoxPreference
            android:key="refresh"
            android:title="@string/check_news"
            android:summary="@string/check_news_description"
            android:defaultValue="true" />
    </PreferenceCategory>

    <PreferenceCategory
        android:title="@string/pref_header_other_general"
        android:key="pref_key_other_settings">

        <EditTextPreference
            android:key="login"
            android:title="@string/pref_title_login"
            android:defaultValue="@string/pref_default_login"
            android:selectAllOnFocus="true"
            android:inputType="textPersonName"
            android:capitalize="words"
            android:singleLine="true"
            android:maxLines="1" />

        <ListPreference
            android:key="notification"
            android:title="@string/pref_title_notifications"
            android:defaultValue="-1"
            android:entries="@array/pref_list_titles"
            android:entryValues="@array/pref_list_values"
            android:negativeButtonText="@null"
            android:positiveButtonText="@null" />

    </PreferenceCategory>

</PreferenceScreen>

Как можно видеть из примера, тут корневой элемент — PreferenceScreen. Внутри него два основных раздела — PreferenceCategory, которые визуально на экране будут выглядеть как две отдельные секции. Каждая PreferenceCategory имеет атрибуты android:title (заголовок секции) и ключ-идентификатор android:key.

Далее идет описание дочерних элементов. В первой секции — это настройка в виде чекбокса CheckBoxPreference. В атрибутах добавляется ключ (для дальнейшего доступа), заголовок, описание и значение по умолчанию (true). Во второй секции значение логина (при нажатии открывается диалог с редактированием EditText) и настройка, связанная с уведомлением (при редактировании будет открываться список с выбором одной из опций).

Добавим разметку для экрана главного Активити:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/to_settings"
        android:id="@+id/button"
        android:onClick="onClick"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/get_settings"
        android:id="@+id/button2"
        android:layout_below="@+id/button"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:onClick="getSettings"/>

</RelativeLayout>

Добавим класс SettingsActivity, наследующее PreferenceActivity:

package ru.androiddocs.preferenceactivity;

import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;

public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            onCreatePreferenceActivity();
        } else {
            onCreatePreferenceFragment();
        }

    }

    /**
     * code for Android < 3 (i.e. API lvl < 11)
     */
    @SuppressWarnings("deprecation")
    private void onCreatePreferenceActivity() {
        addPreferencesFromResource(R.xml.pref_general);
    }

    /**
     * code for Android >= 3 (i.e. API lvl >= 11)
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void onCreatePreferenceFragment() {
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFr())
                .commit();
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class SettingsFr extends PreferenceFragment
    {
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);
        }
    }

}

Здесь в методе onCreate() вы можете увидеть ветвление с проверкой на версию Андроида. Начиная с версии 3.0 (API 11) рекомендуется для создания Активити с настройками использовать фрагменты. Но так как наше приложение нацелено на API, начиная с 9, то мы для старых версий ОС используем depricated подход, вызывая addPreferencesFromResource() напрямую, а не из фрагмент-класса. Т.о., методы, нацеленные на API > 11, помечены аннотацией @TargetApi. Использование такого подхода позволит нам охватить максимум устройств.

Теперь нам остается добавить MainActivity.java

package ru.androiddocs.preferenceactivity;

import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;


public class MainActivity extends ActionBarActivity {

    private static final String LOG_TAG = "my_tag";
    SharedPreferences pref;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pref = PreferenceManager.getDefaultSharedPreferences(this);
    }


    public void onClick(View v) {
        startActivity(new Intent(this, SettingsActivity.class));
    }

    public void getSettings(View v) {

        Log.d(LOG_TAG, "GET SETTINGS: ");
        Log.d(LOG_TAG, "refresh:" + pref.getBoolean("refresh", true));
        Log.d(LOG_TAG, "login:" + pref.getString("login", "").toString());
        Log.d(LOG_TAG, "notification:" + pref.getString("notification", "").toString());
    }
}

В методе onCreate() мы инициализируем объект настроек SharedPreferences pref. В методе onClick() мы запускаем Активити с настройками, а в методе getSettings() выводим текущее значение настроек в логи.

При первом запуске проверим, что у нас в настройках — нажмем на «Получить настройки»:

PreferenceActivity - Активити с настройками

В логах увидим:

PreferenceActivity - Активити с настройками

Теперь переходим к настройкам и редактируем их.

PreferenceActivity - Активити с настройками

Чекбокс снимаем.

PreferenceActivity - Активити с настройками

PreferenceActivity - Активити с настройками

Затем жмем кнопочку Back, возвращаемся на главное Активити и снова выводим настройки в логи:

PreferenceActivity - Активити с настройками

Комментариев: 2 на “PreferenceActivity — Активити с настройками

  1. Борис

    Спасибо.
    Есть вопрос — как сделать, чтобы в preference с чекбоксом тап на тексте приводил к запуску другой activity, а на чекбоксе — собственно к изменению состояния check ?

    Reply
  2. Евгений

    Добрый день!
    Как сделать так, чтобы в Activity настройк отобразился заголовок?? «Settings»
    Где это указывается?

    Reply

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*