Developing a high-quality application for the Android platform is impossible without competent implementation of information storage mechanisms. Users expect that their settings, game progress, cached images and entered text will remain available even after rebooting the device or minimizing the app. Android Studio provides developers with a wide range of tools to solve this problem.

The choice of a specific method depends on the type of data, its volume and security requirements. Making the wrong architecture choices early on can lead to serious performance issues or loss of user information in the future. In this article, we'll take a closer look at the main approaches to persistence.

Understanding the differences between lightweight key storage and complex relational databases is a critical skill for anyone. Android developer. There is no one-size-fits-all solution, so it is important to know the advantages and limitations of each method.

Lightweight storage SharedPreferences

To save simple settings such as theme, first launch status or user preferences, the ideal solution is the mechanism SharedPreferences. This store works on a key-value basis and stores data as an XML file inside the application's internal memory. Using this method is justified when you need to preserve primitive data types: boolean, int, float, long or String.

Working with SharedPreferences is carried out through an object Editor, which allows you to record changes asynchronously or synchronously. The method apply is preferred because it records in the background and does not block the main UI thread, unlike commit. However, it is worth remembering that apply does not guarantee immediate writing to disk, which can be critical in rare scenarios of emergency process termination.

โš ๏ธ Attention: SharedPreferences is not intended for storing large amounts of data or complex objects. An attempt to store a huge JSON there can lead to Application Not Responding (ANR) due to blocking of the thread when reading the entire file into memory.

Modern projects often use a wrapper DataStore, which replaced the outdated API and supports working with coroutines and data streams. However, the classic approach is still widely used in legacy code and simple utilities. The application context is used to access the file.

๐Ÿ’ก

Use prefixes for keys in SharedPreferences (for example, "settings_theme") to avoid naming conflicts when expanding the functionality of the application in the future.

Relational databases with Room Persistence Library

When the application requires storing structured data with complex connections, the library comes to the rescue. It is part of Android Jetpack and provides an abstraction layer over SQLite, allowing you to write less boilerplate code. Room provides compile-time validation of SQL queries, which significantly reduces runtime errors. Room. It is part of Android Jetpack and provides an abstraction layer over SQLite, allowing you to write less boilerplate code. Room provides compile-time checking of SQL queries, which significantly reduces runtime errors.

Room's architecture is based on three main components: the entity (Entity), the data access object (DAO) and the database (Database). An entity describes a table in a database using annotations, and a DAO contains methods for executing queries. Creating a database instance requires using the Singleton pattern to avoid wasting resources on opening connections.

  • ๐Ÿ“ฆ Entity โ€” a class representing a table, where each field corresponds to a column.
  • ๐Ÿ” DAO โ€” an interface or abstract class with methods for CRUD operations (Create, Read, Update, Delete).
  • ๐Ÿ—„๏ธ Database โ€” the main class, (holding) the database and serving as an access point to the DAO.

One of The key advantage of Room is the ability to monitor changes in the database in real time using LiveData or Flow. This allows the user interface to automatically update when data changes, implementing a reactive approach to programming. Migration of database schemas when updating application versions is also supported by built-in mechanisms.

๐Ÿ“Š Which storage method do you use most often?
SharedPreferences
Room (SQLite)
File system
Cloud Firestore
DataStore

Working with the device file system

Sometimes data needs to be saved as separate files, for example, images, audio or documents. Android provides several types of storage, each with its own access and lifetime characteristics. Internal storage (Internal Storage) is private to your application and is deleted when you uninstall it.

To write files to internal memory, use the openFileOutputmethod, which returns an output stream. If you need to provide access to files to other applications or the user, you should use external storage (External Storage). Starting with Android 10 (API level 29), the external memory access model has changed towards Scoped Storage, which limits direct access to arbitrary paths.

File file = new File(context.getFilesDir,"data.txt");

FileOutputStream fos = new FileOutputStream(file);

fos.write(data.getBytes);

fos.close;

It is important to correctly handle exceptions when working with files, since disk space may run out or the file may be damaged. Using buffered streams can significantly improve performance when writing large amounts of information. It is also worth considering the access rights requested in the application manifest.

โš ๏ธ Attention: On devices with Android 11 and higher, direct access to the root of external memory (/sdcard) is blocked. Use MediaStore or Storage Access Framework for working with shared files.
The difference between getExternalFilesDir and getExternalStoragePublicDirectory

getExternalFilesDir returns the path in the application's private folder on external media, which is deleted when the application is uninstalled. getExternalStoragePublicDirectory places the file in a shared folder (for example, Downloads), which remains after the application is uninstalled, but requires special permissions.

Comparing data storage methods

Choosing the right storage tool directly affects the project's architecture and user experience. Below is a table to help you decide on a method based on your data type and performance requirements. Analysis of the characteristics of each approach allows you to avoid architectural errors at the start of development.

Storage method Data type Structure Availability
SharedPreferences Primitives, strings Key-value Application only
Room (SQLite) Complex objects Relational table Application only
Internal files Any (binary) File system Application only
External files Media, documents File system Other apps

Using online databases such as Firebase Realtime Database or Firestore adds another layer of complexity, but ensures synchronization between devices. However, for local operation, the offline mode still requires a local cache, often implemented through the same Room. Hybrid approaches are becoming the standard for modern mobile solutions.

๐Ÿ’ก

For complex queries and large volumes of structured data, always choose Room, and for simple preference flags - SharedPreferences or DataStore.

Security of stored data

Storing sensitive information such as authorization tokens, passwords or personal data requires special precautions. Standard SharedPreferences store data in clear text (XML), making it vulnerable to being read by rooted devices. To protect such information, you must use encryption.

The library Android Jetpack Security provides a class EncryptedSharedPreferencesthat transparently encrypts keys and values โ€‹โ€‹before writing to disk. This solution uses the Android Keystore System to generate and store cryptographic keys protected by the device's hardware. The introduction of encryption minimally changes the code, but dramatically increases the level of security.

  • ๐Ÿ” Use EncryptedSharedPreferences for all tokens and secrets.
  • ๐Ÿ›ก๏ธ Never store passwords in clear text, even in a local database.
  • ๐Ÿ“ฑ Check for root access before recording critical data if your security policy requires it.

In addition to encrypting the content, it is important to protect the database itself. Room allows you to enable encryption via SQLCipher, although this may slightly reduce I/O performance. Always evaluate the risk of data leakage for your specific type of application.

โš ๏ธ Warning: Android Keystore does not protect data if the device is compromised at the kernel or bootloader level. Do not store critical secrets that could lead to financial losses solely on the client.

Data migration and versioning

When an application is updated, the structure of the stored data may change: new fields are added to tables, key names or file formats change. If you don't implement a migration mechanism, your application may crash when trying to read old data. Room provides a convenient API to describe the migration steps between database schema versions.

The migration process requires writing SQL queries that convert the old structure to the new one without losing user information. For example, when adding a new column, you need to run the command ALTER TABLE and fill in the default values. Testing migrations should be a mandatory part of the new version release process.

static final Migration MIGRATION_1_2 = new Migration(1, 2) {

@Override

public void migrate(SupportSQLiteDatabase database) {

database.execSQL("ALTER TABLE Users ADD COLUMN age INTEGER NOT NULL DEFAULT 0");

}

};

For SharedPreferences, migration is usually performed programmatically when the new version is first launched: the application checks the code version and, if necessary, migrates or converts the data to the new format. Ignoring this stage leads to resetting user settings, which negatively affects the appโ€™s rating in the store.

โ˜‘๏ธ Checklist before releasing a database update

Done: 0 / 4

Frequently asked questions (FAQ)

Where are SharedPreferences files physically stored?

Files are stored in the directory /data/data/your.package.app/shared_prefs/. This folder can only be accessed by the app itself or by a root user.

Can Room be used without Android Studio?

No, Room is a library tightly integrated with the Android Jetpack ecosystem and requires the use of Gradle and Android Studio build tools for the correct operation of annotations.

What happens to the data when clearing the application cache?

Clearing the cache (clearCache) deletes only temporary files. Data in SharedPreferences, Room and internal files is preserved. They are deleted only when you clear the data (clearData) or uninstall the application.

How to save a list of objects in SharedPreferences?

You cannot save the list directly. You need to serialize it into a JSON string (using Gson or Moshi) and store this string as a key value.

What is the maximum file size that internal memory can store?

The limit depends on the free space on the user's device and the file system. However, Android can force the process to end if an application consumes too much space in the internal memory.