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

Какие знаешь способы кеширования данных?

2.2 Middle🔥 182 комментариев
#Производительность и оптимизация#Работа с данными

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

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

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

Основные способы кеширования данных в Android-разработке

В Android-разработке кеширование критически важно для производительности, отзывчивости интерфейса и работы приложения без интернета. Я разделю подходы на несколько категорий.

1. In-Memory кеширование (В оперативной памяти)

Ключевая особенность: Максимальная скорость доступа, но данные теряются при завершении работы приложения.

LRU Cache (Least Recently Used)

Наиболее популярная реализация - LruCache из Android SDK. Автоматически удаляет наименее используемые элементы при превышении лимита.

// Пример реализации LruCache для изображений
val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
val cacheSize = maxMemory / 8 // Используем 1/8 доступной памяти

val memoryCache = object : LruCache<String, Bitmap>(cacheSize) {
    override fun sizeOf(key: String, bitmap: Bitmap): Int {
        // Размер в килобайтах
        return bitmap.byteCount / 1024
    }
}

// Сохранение в кеш
memoryCache.put(imageUrl, bitmap)

// Получение из кеша
val cachedBitmap = memoryCache.get(imageUrl)

Коллекции Kotlin/Java

Для простых случаев можно использовать MutableMap или ConcurrentHashMap для потокобезопасности:

val simpleCache = ConcurrentHashMap<String, Any>()

2. Локальное кеширование (На устройстве)

Преимущество: Сохранение данных между запусками приложения.

SharedPreferences

Идеально для небольших простых данных (настройки, флаги, пользовательские предпочтения):

// Современный подход с DataStore (рекомендуется вместо старых SharedPreferences)
val dataStore: DataStore<Preferences> = context.createDataStore(name = "settings")

suspend fun saveToken(token: String) {
    dataStore.edit { preferences ->
        preferences[stringPreferencesKey("auth_token")] = token
    }
}

Файловая система

Прямая работа с файлами через Context:

// Запись в файл
val file = File(context.filesDir, "cached_data.json")
file.writeText(jsonData)

// Чтение из внутреннего хранилища (приватного для приложения)
val internalFile = File(context.filesDir, "cache_file.txt")

// Для больших файлов лучше использовать кеш-директорию
val cacheFile = File(context.cacheDir, "temporary_data.tmp")

Базы данных

  • Room (рекомендуется) - абстракция над SQLite
  • SQLite напрямую
  • Realm - альтернативная NoSQL база
// Room Entity для кеширования
@Entity(tableName = "cached_articles")
data class CachedArticle(
    @PrimaryKey val id: String,
    val title: String,
    val content: String,
    @ColumnInfo(name = "cached_at") val cachedAt: Long
)

// DAO с методами для кеширования
@Dao
interface ArticleDao {
    @Query("SELECT * FROM cached_articles WHERE id = :id")
    suspend fun getById(id: String): CachedArticle?
    
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertOrReplace(article: CachedArticle)
}

3. Сетевой уровень кеширования

HTTP-кеширование

Использование заголовков HTTP для контроля кеширования:

// Настройка OkHttp с кешем
val cacheSize = 10 * 1024 * 1024 // 10 MB
val cache = Cache(File(context.cacheDir, "http_cache"), cacheSize.toLong())

val client = OkHttpClient.Builder()
    .cache(cache)
    .addInterceptor { chain ->
        val request = chain.request()
        // Принудительно берем из кеша если нет сети
        val forceCacheRequest = request.newBuilder()
            .header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7)
            .build()
        chain.proceed(forceCacheRequest)
    }
    .build()

Библиотеки для изображений

  • Glide - автоматическое кеширование в памяти и на диске
  • Coil (Kotlin-first) - современная альтернатива
// Coil автоматически кеширует изображения
imageView.load("https://example.com/image.jpg") {
    memoryCachePolicy(CachePolicy.ENABLED)
    diskCachePolicy(CachePolicy.ENABLED)
    placeholder(R.drawable.placeholder)
}

4. Архитектурные подходы

Repository Pattern с кешированием

Комбинирование источников данных:

class ArticleRepository(
    private val remoteDataSource: RemoteDataSource,
    private val localDataSource: LocalDataSource
) {
    suspend fun getArticle(id: String): Article {
        // Пробуем получить из локального кеша
        val cached = localDataSource.getArticle(id)
        if (cached != null && !isCacheExpired(cached.cachedAt)) {
            return cached
        }
        
        // Если нет в кеше или устарел - загружаем из сети
        val freshArticle = remoteDataSource.getArticle(id)
        
        // Сохраняем в кеш
        localDataSource.saveArticle(freshArticle)
        
        return freshArticle
    }
}

Кеширование в ViewModel

Сохранение состояния UI данных:

class ArticlesViewModel : ViewModel() {
    private val _articles = MutableStateFlow<List<Article>>(emptyList())
    val articles: StateFlow<List<Article>> = _articles.asStateFlow()
    
    // Данные сохраняются при смене конфигурации
    fun loadArticles() {
        viewModelScope.launch {
            _articles.value = repository.getArticles()
        }
    }
}

5. Стратегии инвалидации кеша

  1. TTL (Time To Live) - автоматическое удаление по истечении времени
  2. По событию - сброс кеша при действиях пользователя
  3. По размеру - LRU стратегия
  4. Версионность - инвалидация при изменении структуры данных

Ключевые рекомендации по реализации:

  • Используйте многоуровневое кеширование (память → диск → сеть)
  • Учитывайте ограничения памяти - особенно для изображений
  • Реализуйте очистку кеша при нехватке места
  • Тестируйте стратегии кеширования на реальных устройствах
  • Логируйте попадания в кеш для оптимизации
  • Учитывайте безопасность - не кешируйте чувствительные данные без шифрования

Правильно реализованное кеширование может улучшить пользовательский опыт в несколько раз, снизить потребление трафика и уменьшить нагрузку на серверы.

Какие знаешь способы кеширования данных? | PrepBro