
Операционная система Android использует встроенные механизмы для работы с данными. Одним из основных инструментов для хранения данных является SQLite – легковесная реляционная база данных. Она позволяет приложениям Android эффективно хранить и извлекать данные, не требуя установки дополнительных серверных решений. Важно понимать, как правильно настроить и использовать SQLite для обеспечения стабильности и производительности приложений.
На платформе Android также используется Room – библиотека, которая упрощает взаимодействие с SQLite. Room предоставляет объектно-ориентированную абстракцию, скрывая сложные SQL-запросы и предлагая разработчикам более удобный API. Это делает работу с базами данных более безопасной и менее подверженной ошибкам, особенно в крупных приложениях, где важна точность данных и их эффективное хранение.
Однако, несмотря на доступность таких инструментов, разработчики часто сталкиваются с проблемами, связанными с производительностью базы данных. Например, неправильное использование индексов, частые операции записи или запросы, требующие сложных соединений, могут замедлить работу приложения. Важно учитывать эти факторы при проектировании архитектуры приложения, чтобы обеспечить его бесперебойную работу.
В этой статье рассматриваются ключевые аспекты работы с движками баз данных в Android, включая их настройку, интеграцию и способы оптимизации, что позволяет создать более быстрые и надежные приложения для пользователей.
Особенности использования SQLite в Android
Основные особенности использования SQLite:
- Легковесность – SQLite имеет минимальные системные требования, что идеально подходит для мобильных устройств с ограниченными ресурсами. Он встроен в Android и не требует дополнительных настроек для начала работы.
- Работа с потоками – SQLite поддерживает многозадачность, но операции записи могут блокировать базу данных на время выполнения. Поэтому важно избегать частых операций записи в многозадачных приложениях.
- Низкий уровень абстракции – Для работы с SQLite в Android необходимо писать SQL-запросы вручную. Это требует от разработчика хороших знаний SQL, а также внимательности при обработке ошибок и безопасности запросов.
Для работы с SQLite в Android можно использовать стандартные классы, такие как SQLiteOpenHelper, который помогает управлять жизненным циклом базы данных. Этот класс автоматически создает, обновляет и удаляет базу данных при необходимости.
Некоторые рекомендации по эффективному использованию SQLite:
- Использование транзакций – Все операции записи следует выполнять в рамках транзакций. Это ускоряет выполнение операций и минимизирует риск повреждения данных в случае сбоев.
- Оптимизация запросов – Регулярно проверяйте SQL-запросы на наличие неоптимальных операций, таких как полные сканирования таблиц. Индексы следует использовать для часто запрашиваемых полей.
- Применение кеширования – Для повышения производительности можно использовать кеширование результатов запросов, что особенно важно для операций чтения с большими объемами данных.
Правильное использование SQLite позволяет разработать приложение, которое будет быстро работать с данными, занимать мало места и не перегружать ресурсы устройства. Важно понимать ограничения SQLite, такие как отсутствие сложных механизмов репликации и управления пользователями, и учитывать эти особенности при проектировании архитектуры приложения.
Как настроить и интегрировать SQLite в проект Android

Для интеграции SQLite в проект Android используется стандартная библиотека, которая уже встроена в операционную систему. Процесс настройки и использования SQLite требует выполнения нескольких ключевых шагов.
Шаги для настройки SQLite:
- Создание класса для управления базой данных. Для работы с базой данных необходимо создать класс, который будет наследовать
SQLiteOpenHelper. Этот класс управляет созданием базы данных, ее обновлением и версионированием. - Переопределение методов. В классе
SQLiteOpenHelperнужно переопределить два основных метода:onCreate(SQLiteDatabase db)– вызывается при создании базы данных, здесь создаются таблицы.onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)– вызывается при изменении версии базы данных, используется для обновления структуры таблиц.
- Использование базы данных. После создания класса нужно получить экземпляр базы данных с помощью метода
getWritableDatabase()илиgetReadableDatabase()для записи и чтения данных соответственно.
Пример кода для создания класса базы данных:
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "example.db";
public static final int DATABASE_VERSION = 1;
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_TABLE = "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)";
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS users");
onCreate(db);
}
}
Далее для выполнения операций с базой данных, можно использовать методы insert(), update(), delete() и query(). Например, чтобы добавить нового пользователя:
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", "John Doe");
values.put("email", "john.doe@example.com");
db.insert("users", null, values);
Шаги для интеграции SQLite в проект:
| Шаг | Действие |
|---|---|
| 1 | Добавить класс SQLiteOpenHelper в проект для управления базой данных. |
| 2 | Реализовать метод onCreate() для создания таблиц и структур данных. |
| 3 | Использовать методы getWritableDatabase() и getReadableDatabase() для работы с данными. |
| 4 | Обработать обновления базы данных с помощью метода onUpgrade(). |
Рекомендуется использовать транзакции для работы с базой данных, чтобы избежать ошибок при частых операциях записи:
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
try {
// выполнение операций
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Это обеспечит целостность данных при сбоях и ускорит выполнение запросов. Также стоит внимательно следить за правильным закрытием базы данных, используя метод close() для освобождения ресурсов после завершения работы с базой.
Роль ContentProvider в работе с базами данных Android
ContentProvider в Android используется для обеспечения доступа к данным, хранящимся в приложении, из других приложений или компонентов. Он служит посредником между приложением и базой данных, обеспечивая единый интерфейс для чтения и записи данных. Это особенно важно при работе с локальными базами данных, такими как SQLite, где ContentProvider позволяет безопасно управлять доступом и делиться данными между различными компонентами.
Основная роль ContentProvider заключается в следующем:
- Абстракция доступа к данным – ContentProvider скрывает детали реализации работы с базой данных или другими источниками данных. Разработчик может использовать стандартные операции CRUD (создание, чтение, обновление, удаление), не беспокоясь о реализации конкретных запросов к базе данных.
- Обеспечение безопасности – ContentProvider предоставляет механизмы для контроля доступа к данным. С помощью разрешений (permissions) можно ограничить доступ к данным только для определенных приложений или компонентов, предотвращая несанкционированные операции.
- Поддержка межпрограммного взаимодействия – ContentProvider позволяет различным приложениям взаимодействовать с общими данными. Например, можно создать приложение, которое предоставляет данные другим приложениям, или получить данные из сторонних приложений, используя их ContentProvider.
Для интеграции ContentProvider с базой данных SQLite необходимо создать класс, который наследует ContentProvider. В этом классе определяются методы для работы с данными, такие как insert(), query(), update() и delete(). Пример базовой реализации:
public class MyContentProvider extends ContentProvider {
private SQLiteDatabase database;
private MyDatabaseHelper dbHelper;
@Override
public boolean onCreate() {
dbHelper = new MyDatabaseHelper(getContext());
database = dbHelper.getWritableDatabase();
return true;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
long id = database.insert("users", null, values);
return Uri.parse("content://com.example.provider/users/" + id);
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return database.query("users", projection, selection, selectionArgs, null, null, sortOrder);
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return database.update("users", values, selection, selectionArgs);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return database.delete("users", selection, selectionArgs);
}
@Override
public String getType(Uri uri) {
return "vnd.android.cursor.dir/vnd.com.example.provider.users";
}
}
ContentProvider позволяет приложению получить доступ к данным, используя уникальный URI (Uniform Resource Identifier). Этот URI указывает на конкретный ресурс или таблицу в базе данных. Например, запрос content://com.example.provider/users может использоваться для получения всех данных из таблицы «users».
Рекомендации по использованию ContentProvider:
- Использование стандартных URI – При разработке ContentProvider следует придерживаться общепринятых конвенций для URI, что обеспечит удобство работы с данными другими разработчиками и приложениями.
- Обработка разрешений – При создании ContentProvider важно учесть безопасность данных, предоставляя доступ только авторизованным пользователям с соответствующими разрешениями.
- Оптимизация запросов – Для предотвращения излишней нагрузки на базу данных стоит использовать индексы и другие механизмы для ускорения запросов, особенно при работе с большими объемами данных.
ContentProvider является мощным инструментом для работы с базами данных и позволяет приложению взаимодействовать с внешними данными. Однако его использование требует внимательного подхода к проектированию интерфейса и обеспечения безопасности данных.
Использование Room для работы с базами данных в Android

Основные компоненты Room:
- Entity – представляет таблицу в базе данных. Каждое поле класса, аннотированное как
@Entity, будет соответствовать столбцу в таблице. - DAO (Data Access Object) – интерфейс, который содержит методы для работы с базой данных, такие как insert, update, delete и query. Все методы DAO аннотируются с помощью соответствующих аннотаций, таких как
@Insert,@Update,@Delete,@Query. - Database – абстракция, которая объединяет все сущности и DAOs, предоставляя доступ к базе данных.
Пример работы с Room:
@Entity(tableName = "users")
public class User {
@PrimaryKey(autoGenerate = true)
public int id;
public String name;
public String email;
}
@Dao
public interface UserDao {
@Insert
void insert(User user);
@Query("SELECT * FROM users WHERE id = :userId")
User getUserById(int userId);
@Delete
void delete(User user);
}
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
После создания сущности, DAO и базы данных, можно создать экземпляр RoomDatabase в активности или репозитории:
AppDatabase db = Room.databaseBuilder(context, AppDatabase.class, "app_database") .allowMainThreadQueries() // Только для тестирования, не рекомендуется в продакшн .build();
После этого можно использовать DAO для выполнения операций с базой данных:
UserDao userDao = db.userDao();
userDao.insert(new User("John Doe", "john@example.com"));
User user = userDao.getUserById(1);
Рекомендации по использованию Room:
- Не использовать
allowMainThreadQueries()в продакшн-версии – Операции с базой данных на главном потоке могут вызвать зависания интерфейса, поэтому используйте асинхронные методы или ExecutorService для выполнения запросов в фоновом потоке. - Используйте миграции при обновлении версии базы данных – Room требует миграции при изменении схемы базы данных. Определите методы для обновления базы данных с помощью
@Migration. - Оптимизируйте запросы с помощью индексов – Для часто используемых запросов добавляйте индексы к соответствующим полям в сущностях с помощью аннотации
@Index.
Room обеспечивает чистую и безопасную работу с данными, снижая вероятность ошибок, связанных с прямыми SQL-запросами, и ускоряет разработку Android-приложений. Однако важно правильно организовать работу с потоками и миграциями, чтобы избежать потерь данных и улучшить производительность.
Как оптимизировать запросы к базе данных в Android

Оптимизация запросов к базе данных в Android критична для повышения производительности приложения, особенно при работе с большими объемами данных. Неэффективные запросы могут значительно замедлить работу приложения, что повлияет на пользовательский опыт. Чтобы избежать этого, необходимо учитывать несколько важных аспектов при написании SQL-запросов и проектировании базы данных.
Рекомендации по оптимизации запросов:
- Использование индексов – Индексы значительно ускоряют выполнение запросов, особенно для полей, по которым часто выполняются поисковые операции. Добавьте индекс на те столбцы, которые используются в
WHERE,ORDER BYилиJOINоперациях. - Избегание выборки всех данных – Используйте конкретные поля в запросах вместо
SELECT *. Выборка только нужных полей ускоряет выполнение запроса и уменьшает потребление памяти. - Использование транзакций – Группировка операций в транзакции уменьшает накладные расходы на выполнение каждого запроса. Все операции вставки, обновления и удаления данных должны выполняться внутри транзакции.
- Предотвращение частых операций записи – Запись в базу данных является наиболее ресурсоемкой операцией. Старайтесь уменьшить количество операций записи, используя механизмы кеширования и батчевых вставок.
- Ограничение количества возвращаемых данных – Всегда ограничивайте количество строк, которые возвращаются запросом, используя
LIMITили условия вWHERE, чтобы уменьшить объем данных, который необходимо обрабатывать и передавать.
Пример запроса с ограничением количества данных:
SELECT name, email FROM users WHERE age > 18 LIMIT 100;
Шаблоны оптимизированных запросов:
-- Использование индекса CREATE INDEX idx_user_name ON users(name); -- Ограничение выборки SELECT id, name FROM users WHERE active = 1 ORDER BY name LIMIT 50;
Также важно учитывать работу с соединениями (JOIN). Для улучшения производительности:
- Используйте INNER JOIN, когда необходимо получить данные только из двух таблиц с совпадающими значениями. Это быстрее, чем LEFT JOIN, который возвращает все строки, даже если нет соответствующих данных в другой таблице.
- Используйте индексы на полях, участвующих в соединениях, чтобы ускорить поиск и соединение данных.
Пример оптимизированного запроса с JOIN:
SELECT users.name, orders.amount FROM users INNER JOIN orders ON users.id = orders.user_id WHERE users.active = 1 ORDER BY orders.amount DESC LIMIT 10;
Не забывайте использовать EXPLAIN для анализа планов выполнения запросов. Это позволит увидеть, какие индексы используются, а также поможет выявить узкие места в запросах:
EXPLAIN SELECT name, email FROM users WHERE age > 18;
Использование этих практик позволяет существенно ускорить выполнение запросов и снизить нагрузку на устройство. Важно помнить, что оптимизация работы с базой данных должна быть интегрирована в общую архитектуру приложения для достижения наилучших результатов.
Резервное копирование и восстановление данных в Android

Резервное копирование данных в Android важно для обеспечения их безопасности и восстановления в случае сбоя устройства или потери данных. Операционная система Android предоставляет несколько инструментов для реализации резервного копирования, но для приложений с базами данных важно учитывать специфику работы с локальными данными, такими как данные SQLite.
Основные способы резервного копирования данных в Android:
- Использование встроенного механизма резервного копирования Android – Android предоставляет API для автоматического резервного копирования данных пользователя, включая настройки и файлы приложений, в облако через сервис Google Drive. Для этого нужно использовать
BackupManagerи настроитьandroid:backupAgentв манифесте приложения. - Резервное копирование базы данных SQLite – для создания резервной копии базы данных SQLite можно вручную копировать файл базы данных в другое место, например, на внешнее хранилище или в облачное хранилище.
- Использование сторонних библиотек – для резервного копирования данных и баз данных можно использовать сторонние решения, такие как Firebase, которые автоматически синхронизируют данные с облаком.
Пример резервного копирования базы данных SQLite на внешнее хранилище:
public void backupDatabase(Context context) {
File currentDB = context.getDatabasePath("my_database.db");
File backupDB = new File(Environment.getExternalStorageDirectory(), "backup_my_database.db");
try {
FileInputStream fis = new FileInputStream(currentDB);
FileOutputStream fos = new FileOutputStream(backupDB);
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
fos.flush();
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Для восстановления данных:
- Восстановление базы данных SQLite – восстановление базы данных SQLite происходит путем копирования сохраненного файла базы данных в стандартное место хранения. Это также можно автоматизировать с помощью Android API или сторонних библиотек.
- Восстановление с помощью API Google Backup – если резервное копирование было настроено через Google Drive, данные можно восстановить при следующем входе в систему или при восстановлении устройства.
Рекомендации для эффективного резервного копирования:
- Регулярность – настройте регулярное резервное копирование данных. Это можно реализовать с помощью
WorkManagerдля выполнения периодических задач резервного копирования. - Шифрование данных – для повышения безопасности данных перед отправкой в облако или на внешние носители рекомендуется использовать шифрование базы данных.
- Механизмы восстановления после сбоя – важно предусмотреть механизмы восстановления данных при сбое приложения или устройства. Это может включать автоматическое восстановление данных при первом запуске приложения.
Таким образом, резервное копирование и восстановление данных являются ключевыми аспектами защиты данных на устройствах Android. Независимо от способа, важно обеспечить простоту и надежность процесса восстановления для конечного пользователя.
Проблемы безопасности данных в Android при использовании баз данных

Основные проблемы безопасности:
- Отсутствие шифрования данных – Базы данных, такие как SQLite, не предлагают встроенной защиты данных. Без шифрования любой злоумышленник, получивший доступ к файловой системе устройства, может извлечь данные напрямую из базы.
- Ненадежное хранилище данных – Данные, хранящиеся в незащищенных местах (например, на внешнем хранилище), могут быть легко украдены, если устройство потеряно или украдено.
- Неправильное управление правами доступа – В Android доступ к данным приложениям может быть недостаточно ограничен, что позв
Советы по тестированию баз данных в приложениях Android

Рекомендации по тестированию баз данных:
- Использование in-memory базы данных – Для юнит-тестов следует использовать in-memory базы данных. Это позволяет ускорить тестирование, избегая необходимости взаимодействовать с реальной файловой системой, и делает тесты независимыми от данных, хранящихся на устройстве. В Android можно использовать
Room.inMemoryDatabaseBuilder()для создания временной базы данных.
Пример использования in-memory базы данных в Room:
@Test public void testDatabase() { // Создаем in-memory базу данных для теста AppDatabase db = Room.inMemoryDatabaseBuilder(context, AppDatabase.class) .allowMainThreadQueries() // для тестирования на главном потоке .build(); UserDao userDao = db.userDao(); // Добавляем данные User user = new User("John", "john@example.com"); userDao.insert(user); // Проверяем, что данные добавлены User fetchedUser = userDao.getUserById(user.getId()); assertEquals(user.getName(), fetchedUser.getName()); }- Тестирование миграций – При изменении схемы базы данных важно проверять миграции. Используйте инструмент
MigrationTestHelperдля проверки миграций и предотвращения потери данных при обновлении версии базы данных.
Пример теста миграции:
@Test public void testDatabaseMigration() throws IOException { // Используем MigrationTestHelper для проверки миграции Migration migration = new Migration(1, 2) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { database.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0"); } }; // Создаем базу данных и проверяем миграцию Room.databaseBuilder(context, AppDatabase.class, "test-db") .addMigrations(migration) .build(); }- Покрытие тестами всех операций с данными – Важно протестировать все операции с базой данных, включая вставку, обновление, удаление и выборку данных. Убедитесь, что каждый метод DAO (insert, update, delete, query) работает корректно с различными входными данными и краевыми случаями.
Пример тестирования метода удаления:
@Test public void testDeleteUser() { User user = new User("Jane", "jane@example.com"); userDao.insert(user); // Удаляем пользователя userDao.delete(user); // Проверяем, что пользователь удален User fetchedUser = userDao.getUserById(user.getId()); assertNull(fetchedUser); }- Использование мок-объектов – Для тестирования DAO или репозиториев, которые взаимодействуют с базой данных, можно использовать мок-объекты. Это позволяет имитировать поведение базы данных без ее реального использования и ускоряет процесс тестирования.
Пример использования мок-объектов с
Mockito:@Test public void testUserDaoMock() { // Мокаем DAO UserDao mockUserDao = mock(UserDao.class); // Создаем тестового пользователя User user = new User("Test", "test@example.com"); // Настроим мок для возврата пользователя when(mockUserDao.getUserById(1)).thenReturn(user); // Проверяем, что возвращаемый пользователь соответствует ожиданиям User fetchedUser = mockUserDao.getUserById(1); assertEquals(user.getName(), fetchedUser.getName()); }- Тестирование производительности запросов – Важно протестировать производительность запросов, особенно если приложение работает с большими объемами данных. Используйте
Benchmarkдля замера времени выполнения критичных запросов и оптимизации их работы.
Пример измерения производительности запроса:
@Test public void testQueryPerformance() { long startTime = System.currentTimeMillis(); // Выполнение ресурсоемкого запроса userDao.getAllUsers(); long endTime = System.currentTimeMillis(); long duration = endTime - startTime; // Проверяем, что запрос выполняется в приемлемое время assertTrue(duration < 1000); }Тестирование баз данных – это не только проверка функциональности, но и обеспечение надежности, производительности и безопасности данных. Используя эти методы и инструменты, можно эффективно тестировать работу с базами данных и предотвратить множество потенциальных проблем на этапе разработки.
Вопрос-ответ:
Что такое движок баз данных в Android и какие его особенности?
Движок баз данных в Android — это система для хранения и управления данными, используемая для обработки локальных данных приложений. Наиболее популярный движок — SQLite, который предоставляет базовую функциональность для работы с реляционными базами данных. Особенности использования SQLite включают низкое потребление ресурсов и интеграцию с Android через стандартные API. SQLite поддерживает операции CRUD (создание, чтение, обновление, удаление) и предоставляет простой интерфейс для работы с данными.
Как в Android настроить и использовать SQLite для хранения данных?
Для настройки SQLite в Android необходимо создать класс, который наследует SQLiteOpenHelper. Этот класс отвечает за создание и обновление базы данных. В нем нужно переопределить методы
onCreate()иonUpgrade(), которые выполняются при создании и изменении версии базы данных. После этого можно использовать методыgetWritableDatabase()иgetReadableDatabase()для чтения и записи данных.Почему стоит использовать ContentProvider для работы с базами данных в Android?
ContentProvider в Android используется для обмена данными между различными приложениями. Он предоставляет абстракцию над базой данных, позволяя безопасно управлять доступом к данным и обеспечивать взаимодействие с другими приложениями. Использование ContentProvider помогает избежать ошибок, связанных с прямым доступом к базе данных, и повышает безопасность данных, контролируя доступ через разрешения.
Как обеспечить безопасность данных в Android при использовании баз данных?
Для обеспечения безопасности данных в Android при работе с базами данных важно использовать шифрование данных, например, через библиотеку SQLCipher, которая добавляет шифрование на уровне базы данных. Также необходимо следить за правильным управлением правами доступа, используя разрешения для ограничения доступа к данным. Рекомендуется хранить данные в защищенных местах, таких как
Keystore, и использовать безопасные соединения для передачи данных между приложением и сервером.Как тестировать базу данных в Android-приложении?
Для тестирования базы данных в Android рекомендуется использовать in-memory базу данных, что позволяет ускорить процесс и избежать зависимости от реального хранилища. Также стоит тестировать миграции базы данных с помощью
MigrationTestHelper, чтобы гарантировать корректное обновление схемы при изменении версии базы. Важно покрывать тестами все основные операции с данными: вставку, обновление, удаление и выборку, а также производительность запросов.Какие преимущества предоставляет использование SQLite в Android-приложениях?
SQLite — это встроенная база данных, которая отлично подходит для хранения данных на устройствах с ограниченными ресурсами, таких как смартфоны и планшеты. Она легковесная, не требует сложной установки и предоставляет быстрый доступ к данным. SQLite идеально подходит для приложений, которым нужно работать с локальными данными, такими как списки, настройки или небольшие объемы информации. Кроме того, она полностью интегрирована в Android SDK, что упрощает разработку и использование.
Как настроить резервное копирование базы данных SQLite в Android?
Для резервного копирования базы данных SQLite в Android можно использовать несколько подходов. Один из вариантов — копировать файл базы данных в безопасное место, например, на внешнее хранилище или облако. Для этого можно воспользоваться стандартными классами Java для работы с файлами, такими как
FileInputStreamиFileOutputStream. Также стоит предусмотреть механизм восстановления данных, который позволит загрузить резервную копию при необходимости. Важно учесть, что база данных должна быть зашифрована, если она содержит конфиденциальную информацию, чтобы избежать утечек данных. - Использование in-memory базы данных – Для юнит-тестов следует использовать in-memory базы данных. Это позволяет ускорить тестирование, избегая необходимости взаимодействовать с реальной файловой системой, и делает тесты независимыми от данных, хранящихся на устройстве. В Android можно использовать
