Как реализовать кэширование данных?
Кэширование данных в Xamarin-приложении — это техника временного хранения информации (например, данных из API, изображений или пользовательских настроек) с целью повышения производительности, снижения потребления трафика и обеспечения оффлайн-доступа. Правильная реализация кэша улучшает отклик интерфейса, уменьшает нагрузку на сеть и сервер и позволяет работать в условиях нестабильного или отсутствующего подключения.
Виды кэширования
-
Память (In-memory cache)
Быстрый, но временный кэш в оперативной памяти. Данные теряются при перезапуске приложения. -
Кэш на диске (Disk cache)
Хранит данные на файловой системе устройства или в базе данных (например, SQLite). -
Кэш изображений
Используется при загрузке и отображении картинок, особенно с удалённых серверов. -
Кэширование настроек (Key-Value)
Для хранения пользовательских данных, конфигураций, токенов авторизации. -
Оффлайн-кэш (Persisted cache)
Для обеспечения доступа к данным без подключения к интернету.
Подходы и библиотеки для кэширования
1. Xamarin.Essentials: Preferences
Подходит для простого кэширования строк, чисел, bool и дат:
Preferences.Set("username", "JohnDoe");
string name = Preferences.Get("username", "default");
Не подходит для хранения больших объёмов или сложных объектов.
2. File-based caching
Можно сохранять сериализованные данные в файлы:
string path = Path.Combine(FileSystem.AppDataDirectory, "data.json");
File.WriteAllText(path, JsonConvert.SerializeObject(data));
Чтение:
if (File.Exists(path))
{
string content = File.ReadAllText(path);
var result = JsonConvert.DeserializeObject<MyModel>(content);
}
Подходит для структурированных данных, полученных от API.
3. SQLite / LiteDB / Realm
Используются как кэш-хранилища, особенно при работе с API.
Пример с SQLite:
public class Article
{
\[PrimaryKey, AutoIncrement\]
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
Сохранение:
await \_db.InsertOrReplaceAsync(article);
Чтение из кэша:
var articles = await \_db.Table<Article>().ToListAsync();
Можно организовать стратегию "кэш → сеть", проверяя наличие записи и срок её актуальности.
4. Akavache
Кросс-платформенная библиотека кэширования с поддержкой экспирации и сериализации.
Установка:
Install-Package Akavache
Инициализация:
BlobCache.ApplicationName = "MyApp";
Сохранение:
await BlobCache.LocalMachine.InsertObject("articles", myList, TimeSpan.FromHours(1));
Чтение:
var articles = await BlobCache.LocalMachine.GetObject<List<Article>>("articles");
Удаление:
await BlobCache.LocalMachine.Invalidate("articles");
5. Image Caching: FFImageLoading / Glide / Picasso
Для оптимизации загрузки изображений из интернета:
FFImageLoading (устаревшая, но ещё используется):
<ffimageloading:CachedImage
Source="https://example.com/image.jpg"
CacheDuration="30"
DownsampleToViewSize="true"
Aspect="AspectFill"/>
Автоматически кэширует изображения на диске.
Стратегии кэширования
1. Cache-first
Проверка наличия кэшированных данных перед сетевым запросом:
var cached = await TryLoadFromCache();
if (cached != null)
return cached;
var data = await LoadFromApi();
await SaveToCache(data);
return data;
2. Network-first с fallback
Загрузка с сервера, при ошибке — из кэша:
try
{
var data = await LoadFromApi();
await SaveToCache(data);
return data;
}
catch
{
return await TryLoadFromCache();
}
3. Stale-while-revalidate
Отображение кэша, фоновая загрузка обновлений:
var cached = await LoadFromCache();
Show(cached);
_ = Task.Run(async () => {
var fresh = await LoadFromApi();
await SaveToCache(fresh);
UpdateUI(fresh);
});
Контроль актуальности кэша
-
Срок действия (TTL): данные кэша устаревают через заданный период.
-
Версионирование: добавление Version или LastModified для сравнения с сервером.
-
Явная очистка: вручную или по событию (Logout, Refresh, Pull-to-Refresh).
Пример: Кэширование данных из REST API
public async Task<List<Product>> GetProductsAsync()
{
var cacheKey = "products";
if (Connectivity.NetworkAccess != NetworkAccess.Internet)
{
// оффлайн — читаем из кэша
return await BlobCache.LocalMachine.GetObject<List<Product>>(cacheKey);
}
var response = await \_httpClient.GetStringAsync("https://example.com/api/products");
var data = JsonConvert.DeserializeObject<List<Product>>(response);
await BlobCache.LocalMachine.InsertObject(cacheKey, data, TimeSpan.FromMinutes(30));
return data;
}
Удаление устаревшего кэша
Очищение всех данных:
await BlobCache.LocalMachine.InvalidateAll();
Удаление конкретного ключа:
await BlobCache.LocalMachine.Invalidate("articles");
Очистка по сроку действия выполняется автоматически при извлечении объекта.
Использование DependencyService для абстрагирования кэш-логики
Можно создать интерфейс:
public interface ICacheService
{
Task SaveAsync<T>(string key, T obj);
Task<T> LoadAsync<T>(string key);
Task RemoveAsync(string key);
}
А затем реализовать его с использованием Akavache, Preferences или другой технологии.
Ошибки и подводные камни
-
Избыточное кэширование может занимать много места и замедлять работу.
-
Несинхронизированные данные между кэшем и сервером могут вводить пользователя в заблуждение.
-
Проблемы сериализации при обновлении моделей могут привести к сбоям при чтении.
-
Плохая стратегия очистки кэша может привести к утечкам памяти и устаревшим данным.
-
Нарушение конфиденциальности при кэшировании личных данных без шифрования.
Заключение о реализации
В Xamarin можно реализовать кэширование любым удобным способом — от простого сохранения в файлы до полноценного слоя с TTL, оффлайн-доступом и стратегиями обновления. Выбор зависит от сложности данных, требований к UX и бизнес-логики. Легкие ключ-значение данные лучше хранить в Preferences, API-ответы — в SQLite или Akavache, а изображения — в FFImageLoading. Кэш должен быть прозрачным для пользователя и не требовать от него дополнительных действий.