← Назад к вопросам

Как сохранишь данные, не используя Room и Shared Preferense

2.3 Middle🔥 192 комментариев
#Работа с данными

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Основные подходы к хранению данных без Room и SharedPreferences

Для сохранения данных в Android без использования Room и SharedPreferences существует несколько альтернативных подходов. Каждый из них имеет свои особенности, преимущества и идеальные сценарии использования.

1. SQLite через SQLiteOpenHelper

SQLite — это встроенная реляционная база данных, к которой можно обращаться напрямую через Android SDK.

class MyDatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
    
    companion object {
        private const val DATABASE_NAME = "my_database.db"
        private const val DATABASE_VERSION = 1
        const val TABLE_NAME = "users"
        const val COLUMN_ID = "id"
        const val COLUMN_NAME = "name"
    }
    
    override fun onCreate(db: SQLiteDatabase) {
        val createTable = """
            CREATE TABLE $TABLE_NAME (
                $COLUMN_ID INTEGER PRIMARY KEY AUTOINCREMENT,
                $COLUMN_NAME TEXT NOT NULL
            )
        """.trimIndent()
        db.execSQL(createTable)
    }
    
    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
        onCreate(db)
    }
    
    fun addUser(name: String): Long {
        val db = this.writableDatabase
        val values = ContentValues().apply {
            put(COLUMN_NAME, name)
        }
        return db.insert(TABLE_NAME, null, values)
    }
    
    fun getAllUsers(): List<String> {
        val users = mutableListOf<String>()
        val db = this.readableDatabase
        val cursor = db.rawQuery("SELECT * FROM $TABLE_NAME", null)
        
        if (cursor.moveToFirst()) {
            do {
                val name = cursor.getString(cursor.getColumnIndex(COLUMN_NAME))
                users.add(name)
            } while (cursor.moveToNext())
        }
        cursor.close()
        return users
    }
}

Преимущества:

  • Полный контроль над SQL-запросами
  • Работа с реляционными данными
  • Сложные запросы с JOIN и агрегацией

Недостатки:

  • Большой объем boilerplate-кода
  • Необходимость ручного управления версиями
  • Отсутствие проверки типов на уровне компиляции

2. Файловое хранилище

Внутреннее хранилище (Internal Storage)

class FileStorageManager(private val context: Context) {
    
    private val fileName = "app_data.txt"
    
    fun saveData(data: String): Boolean {
        return try {
            context.openFileOutput(fileName, Context.MODE_PRIVATE).use { outputStream ->
                outputStream.write(data.toByteArray())
            }
            true
        } catch (e: IOException) {
            false
        }
    }
    
    fun loadData(): String? {
        return try {
            context.openFileInput(fileName).use { inputStream ->
                inputStream.bufferedReader().use { reader ->
                    reader.readText()
                }
            }
        } catch (e: FileNotFoundException) {
            null
        }
    }
}

Внешнее хранилище (External Storage)

fun saveToExternalStorage(data: String, fileName: String): Boolean {
    return if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
        val file = File(Environment.getExternalStorageDirectory(), fileName)
        try {
            file.writeText(data)
            true
        } catch (e: IOException) {
            false
        }
    } else {
        false
    }
}

3. ContentProvider

ContentProvider — это механизм для обмена данными между приложениями с использованием URI.

class MyContentProvider : ContentProvider() {
    
    private lateinit var databaseHelper: SQLiteOpenHelper
    
    override fun onCreate(): Boolean {
        databaseHelper = MyDatabaseHelper(context!!)
        return true
    }
    
    override fun query(
        uri: Uri,
        projection: Array<String>?,
        selection: String?,
        selectionArgs: Array<String>?,
        sortOrder: String?
    ): Cursor {
        val db = databaseHelper.readableDatabase
        return db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder)
    }
    
    override fun insert(uri: Uri, values: ContentValues?): Uri {
        val db = databaseHelper.writableDatabase
        val id = db.insert(TABLE_NAME, null, values)
        return Uri.parse("content://${AUTHORITY}/$TABLE_NAME/$id")
    }
    
    // Другие методы: update, delete, getType
}

4. NoSQL базы данных

Realm

// Инициализация Realm
Realm.init(context)
val config = RealmConfiguration.Builder()
    .name("myrealm.realm")
    .schemaVersion(1)
    .build()
val realm = Realm.getInstance(config)

// Сохранение данных
realm.executeTransaction { realmInstance ->
    val user = realmInstance.createObject(User::class.java)
    user.id = 1
    user.name = "John Doe"
}

// Чтение данных
val users = realm.where(User::class.java).findAll()

ObjectBox

// Настройка ObjectBox
val boxStore = MyObjectBox.builder()
    .androidContext(context)
    .build()

// Сохранение объекта
val userBox = boxStore.boxFor(User::class.java)
val user = User(name = "Alice")
val id = userBox.put(user)

// Запрос объектов
val users = userBox.query().equal(User_.name, "Alice").build().find()

5. Кэширование в оперативной памяти

object MemoryCache {
    private val cache = mutableMapOf<String, Any>()
    
    fun <T> put(key: String, value: T) {
        cache[key] = value as Any
    }
    
    @Suppress("UNCHECKED_CAST")
    fun <T> get(key: String): T? {
        return cache[key] as? T
    }
    
    fun clear() {
        cache.clear()
    }
}

6. Сетевое хранилище через API

class RemoteStorage(private val retrofitService: ApiService) {
    
    suspend fun saveDataRemotely(data: UserData): Result<Boolean> {
        return try {
            val response = retrofitService.saveUserData(data)
            if (response.isSuccessful) {
                Result.success(true)
            } else {
                Result.failure(Exception("Server error: ${response.code()}"))
            }
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    suspend fun loadDataRemotely(userId: String): Result<UserData> {
        return try {
            val response = retrofitService.getUserData(userId)
            if (response.isSuccessful) {
                Result.success(response.body()!!)
            } else {
                Result.failure(Exception("Failed to load data"))
            }
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

Критерии выбора подхода

Когда использовать каждое решение:

  • SQLiteOpenHelper — для сложных реляционных данных с необходимостью выполнения SQL-запросов
  • Файловое хранилище — для простых структур данных, логов, кэширования контента
  • ContentProvider — при необходимости делиться данными с другими приложениями
  • NoSQL базы — для работы с объектами без ORM, когда нужна высокая производительность
  • MemoryCache — для временного хранения часто используемых данных
  • Сетевое хранилище — когда данные должны быть синхронизированы на сервере

Важные замечания

  1. Безопасность: Для хранения чувствительных данных используйте Android Keystore
  2. Производительность: Файловые операции на внешнем хранилище могут быть медленными
  3. Размер данных: Реляционные базы эффективны для структурированных данных среднего объема
  4. Синхронизация: При использовании удаленного хранилища реализуйте механизм автономной работы

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

Как сохранишь данные, не используя Room и Shared Preferense | PrepBro