← Назад к вопросам
Как сохранишь данные, не используя 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 — для временного хранения часто используемых данных
- Сетевое хранилище — когда данные должны быть синхронизированы на сервере
Важные замечания
- Безопасность: Для хранения чувствительных данных используйте Android Keystore
- Производительность: Файловые операции на внешнем хранилище могут быть медленными
- Размер данных: Реляционные базы эффективны для структурированных данных среднего объема
- Синхронизация: При использовании удаленного хранилища реализуйте механизм автономной работы
Выбор конкретного способа хранения зависит от требований проекта: сложности данных, требований к производительности, необходимости синхронизации и уровня доступа к данным.