Назад к вопросам
Junior
82
questionbank

Как происходит хранение данных в Android?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

В Android для хранения данных используются различные механизмы, выбор которых зависит от типа данных, их размера, требований к безопасности и доступности.

Основные способы хранения данных:

  1. SharedPreferences:

    • Для небольших объемов примитивных данных (boolean, int, float, long, String, Set<String>).
    • Хранятся в XML-файлах.
    • Не предназначены для одновременного доступа из нескольких процессов.
    // Получение SharedPreferences
    val sharedPref = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
    
    // Сохранение данных
    with (sharedPref.edit()) {
        putBoolean("is_logged_in", true)
        putString("username", "user123")
        apply() // Асинхронное сохранение
        // commit() // Синхронное сохранение
    }
    
    // Чтение данных
    val isLoggedIn = sharedPref.getBoolean("is_logged_in", false)
    val username = sharedPref.getString("username", null)
    
  2. Internal Storage:

    • Для хранения приватных файлов приложения.
    • Файлы доступны только самому приложению.
    • Автоматически удаляются при удалении приложения.
    // Запись в файл
    val filename = "my_data.txt"
    val fileContents = "Some data to write."
    context.openFileOutput(filename, Context.MODE_PRIVATE).use {
        it.write(fileContents.toByteArray())
    }
    
    // Чтение из файла
    context.openFileInput(filename).bufferedReader().useLines { lines ->
        lines.forEach {
            // Обработка строки
        }
    }
    
  3. External Storage:

    • Для хранения общедоступных данных (фото, видео, документы).
    • Файлы могут быть доступны другим приложениям и пользователю через файловый менеджер.
    • Может отсутствовать или быть не смонтировано, поэтому необходимо проверять его доступность.
    • Начиная с Android 10, используется Scoped Storage для ограничения доступа к файлам других приложений.
    // Проверка доступности внешнего хранилища
    fun isExternalStorageWritable(): Boolean {
        return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
    }
    
    fun isExternalStorageReadable(): Boolean {
        return Environment.getExternalStorageState() in
                setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
    }
    
    // Получение директории для сохранения файлов (например, для документов)
    val directory = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
    val file = File(directory, "my_external_file.txt")
    
    // Запись в файл на внешнем хранилище
    FileWriter(file).use { writer ->
        writer.write("Data on external storage.")
    }
    
  4. SQLite Databases:

    • Для хранения структурированных данных в реляционном виде.
    • Поддерживает SQL-запросы.
    • Используется для более сложных сценариев хранения данных.
    • Для упрощения работы с базами данных используются библиотеки, такие как Room Persistence Library.

    Пример использования Room:

    // Определение сущности
    @Entity
    data class User(
        @PrimaryKey val uid: Int,
        @ColumnInfo(name = "first_name") val firstName: String?,
        @ColumnInfo(name = "last_name") val lastName: String?
    )
    
    // Определение DAO (Data Access Object)
    @Dao
    interface UserDao {
        @Query("SELECT * FROM user")
        fun getAll(): List<User>
    
        @Query("SELECT * FROM user WHERE uid IN (:userIds)")
        fun loadAllByIds(userIds: IntArray): List<User>
    
        @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
               "last_name LIKE :last LIMIT 1")
        fun findByName(first: String, last: String): User
    
        @Insert
        fun insertAll(vararg users: User)
    
        @Delete
        fun delete(user: User)
    }
    
    // Определение базы данных Room
    @Database(entities = [User::class], version = 1)
    abstract class AppDatabase : RoomDatabase() {
        abstract fun userDao(): UserDao
    }
    
    // Использование базы данных
    val db = Room.databaseBuilder(
        applicationContext,
        AppDatabase::class.java, "database-name"
    ).build()
    
    val userDao = db.userDao()
    val users: List<User> = userDao.getAll()
    
  5. Content Providers:

    • Позволяют приложениям обмениваться данными с другими приложениями.
    • Используются для доступа к системным данным (контакты, медиа) или предоставления своих данных другим приложениям.
    • Требуют определения URI (Uniform Resource Identifier) для идентификации данных.
    // Пример запроса к контактам с использованием ContentResolver
    val cursor: Cursor? = contentResolver.query(
        ContactsContract.Contacts.CONTENT_URI,
        null, // Проекция (какие столбцы вернуть)
        null, // Критерии выбора (WHERE clause)
        null, // Аргументы выбора
        null  // Сортировка
    )
    
    cursor?.use {
        while (it.moveToNext()) {
            val contactId = it.getLong(it.getColumnIndexOrThrow(ContactsContract.Contacts._ID))
            // Доступ к другим данным контакта
        }
    }
    
  6. DataStore:

    • Более современная и гибкая альтернатива SharedPreferences.
    • Использует Kotlin Coroutines и Flow для асинхронной работы с данными.
    • Доступен в двух реализациях: Preferences DataStore (для примитивных данных) и Proto DataStore (для хранения объектов с использованием Protocol Buffers).

    Пример использования Preferences DataStore:

    private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
    
    // Сохранение данных (в CoroutineScope)
    suspend fun saveSetting(key: Preferences.Key<Boolean>, value: Boolean) {
        context.dataStore.edit { settings ->
            settings[key] = value
        }
    }
    
    // Чтение данных (в CoroutineScope)
    val exampleSetting: Flow<Boolean> = context.dataStore.data
        .map { preferences ->
            preferences[booleanPreferencesKey("example_setting")] ?: false
        }
    

Выбор оптимального способа хранения данных зависит от конкретных требований вашего приложения.