Створення та отримання налаштувань SharedPreferences

Нерідко додатку потрібно зберігати невеликі шматки даних для подальшого використання, наприклад, дані про користувача, налаштування конфігурації тощо. Для цього в Android існує концепція Preferences або налаштувань. Налаштування являють собою групу пар ключ-значення, які використовуються додатком.

Як значення можуть виступати дані наступних типів: Boolean, Float, Integer, Long, String, набір рядків.

Налаштування є загальними для всіх activity в додатку, але також можуть бути і налаштування безпосередньо для окремих activity.

Налаштування зберігаються в xml-файлах у незашифрованому вигляді в локальному сховищі. Вони невидимі, тому для простого користувача недоступні.

При роботі з налаштуваннями слід враховувати наступні моменти. Оскільки вони зберігаються в незашифрованому вигляді, не рекомендується зберігати в них чутливі дані типу паролів чи номерів кредитних карток. Крім того, вони представляють дані, асоційовані з додатком, і через панель управління додатком в Налаштуваннях ОС користувач може видалити ці дані.

Загальні налаштування

Для роботи з розділеними налаштуваннями в класі Activity (точніше в його базовому класі Context) є метод getSharedPreferences():

import android.content.SharedPreferences;
 
//...........................
 
SharedPreferences settings = getSharedPreferences("PreferencesName", MODE_PRIVATE);

Перший параметр методу вказує на назву налаштувань. В даному випадку назва - "PreferencesName". Якщо налаштувань з таким ім'ям немає, вони створюються при виклику цього методу. Другий параметр вказує на режим доступу. В даному випадку режим описано константою MODE_PRIVATE.

Клас android.content.SharedPreferences надає низку методів для управління налаштуваннями:

  • contains(String key): повертає true, якщо в налаштуваннях збережено значення з ключем key
  • getAll(): повертає всі збережені в налаштуваннях значення
  • getBoolean(String key, boolean defValue): повертає з налаштувань значення типу Boolean, яке має ключ key. Якщо елемент з таким ключем не знайдено, повертається значення defValue, передане другим параметром
  • getFloat(String key, float defValue): повертає значення типу float з ключем key. Якщо елемент з таким ключем не знайдено, повертається значення defValue
  • getInt(String key, int defValue): повертає значення типу int з ключем key
  • getLong(String key, long defValue): повертає значення типу long з ключем key
  • getString(String key, String defValue): повертає рядкове значення з ключем key
  • getStringSet(String key, Set<String> defValues): повертає масив рядків з ключем key
  • edit(): повертає об'єкт SharedPreferences.Editor, який використовується для редагування налаштувань

Для управління налаштуваннями використовується об'єкт класу SharedPreferences.Editor, який повертається методом edit(). Він визначає наступні методи:

  • clear(): видаляє всі налаштування
  • remove(String key): видаляє з налаштувань значення з ключем key
  • putBoolean(String key, boolean value): додає в налаштування значення типу boolean з ключем key
  • putFloat(String key, float value): додає в налаштування значення типу float з ключем key
  • putInt(String key, int value): додає в налаштування значення типу int з ключем key
  • putLong(String key, long value): додає в налаштування значення типу long з ключем key
  • putString(String key, String value): додає в налаштування рядок з ключем key
  • putStringSet(String key, Set<String> values): додає в налаштування масив рядків
  • commit(): підтверджує всі зміни в налаштуваннях
  • apply(): також, як і метод commit(), підтверджує всі зміни в налаштуваннях, однак змінений об'єкт SharedPreferences спочатку зберігається в тимчасовій пам'яті, і лише потім в результаті асинхронної операції записується на мобільний пристрій

Розглянемо приклад збереження й отримання налаштувань у застосунку. Визначимо у файлі activity_main.xml наступний користувацький інтерфейс:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 
    <EditText
        android:id="@+id/nameBox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="Введіть ім'я"
        app:layout_constraintBottom_toTopOf="@id/saveButton"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <Button
        android:id="@+id/saveButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Зберегти"
        android:onClick="saveName"
        app:layout_constraintBottom_toTopOf="@id/nameView"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/nameBox"/>
 
    <TextView
        android:id="@+id/nameView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        app:layout_constraintBottom_toTopOf="@id/getButton"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/saveButton"/>
    <Button
        android:id="@+id/getButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Отримати ім'я"
        android:onClick="getName"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/nameView"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

На екрані будуть дві кнопки - для збереження і для виведення раніше збереженого значення, а також поле для введення і текстове поля для виведення збереженого налаштування.

Визначимо методи обробники кнопок у класі MainActivity:

package com.example.settingsapp;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
 
    private static final String PREFS_FILE = "Account";
    private static final String PREF_NAME = "Name";
    SharedPreferences settings;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        settings = getSharedPreferences(PREFS_FILE, MODE_PRIVATE);
    }
 
    public void saveName(View view) {
        // отримуємо введене ім'я
        EditText nameBox = findViewById(R.id.nameBox);
        String name = nameBox.getText().toString();
        // зберігаємо його в налаштуваннях
        SharedPreferences.Editor prefEditor = settings.edit();
        prefEditor.putString(PREF_NAME, name);
        prefEditor.apply();
    }
 
    public void getName(View view) {
        // отримуємо збережене ім'я
        TextView nameView = findViewById(R.id.nameView);
        String name = settings.getString(PREF_NAME, "не визначено");
        nameView.setText(name);
    }
}

За відсутності налаштувань під час спроби їх отримати, додаток виведе значення за замовчуванням: Тепер збережемо і виведемо заново збережене значення: Нерідко виникає завдання автоматично зберігати дані, що вводяться, при виході користувача з activity. Для цього ми можемо перевизначити метод onPause:

package com.example.settingsapp;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
 
public class MainActivity extends AppCompatActivity {
 
    private static final String PREFS_FILE = "Account";
    private static final String PREF_NAME = "Name";
    EditText nameBox;
    SharedPreferences settings;
    SharedPreferences.Editor prefEditor;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        nameBox = findViewById(R.id.nameBox);
        settings = getSharedPreferences(PREFS_FILE, MODE_PRIVATE);
 
        // отримуємо налаштування
        String name = settings.getString(PREF_NAME,"");
        nameBox.setText(name);
    }
 
    @Override
    protected void onPause(){
        super.onPause();
 
        String name = nameBox.getText().toString();
        // зберігаємо в налаштуваннях
        prefEditor = settings.edit();
        prefEditor.putString(PREF_NAME, name);
        prefEditor.apply();
    }
 
    public void saveName(View view) {
 
    }
 
    public void getName(View view) {
 
    }
}

Приватні налаштування

Окрім загальних налаштувань, кожна activity може використовувати приватні налаштування, до яких доступ з інших activity буде неможливий. Для отримання налаштувань рівня activity використовується метод getPreferences(MODE_PRIVATE):

import android.content.SharedPreferences;
//........................
SharedPreferences settings = getPreferences(MODE_PRIVATE);

Тобто, на відміну від загальних налаштувань, тут не використовується назва групи налаштувань в якості першого параметра, як в методі getSharedPreferences(). Однак вся решта робота по додаванню, отриманню та зміненню налаштувань буде аналогічна роботі з загальними налаштуваннями.