Unikaj pobierania niezoptymalizowanych plików

Niektórzy użytkownicy Twojej aplikacji mają ograniczony dostęp do internetu lub mają ograniczoną ilość informacji, które mogą pobrać na swoje urządzenia. Aby zachęcić użytkowników do częstszego korzystania z aplikacji, możesz ograniczyć ilość danych, które musi ona pobrać.

Podstawowym sposobem zmniejszenia liczby pobrań jest pobieranie tylko tego, co jest potrzebne. W kontekście danych oznacza to wdrożenie interfejsów API REST, które pozwalają na określanie kryteriów zapytań ograniczających zwracane dane za pomocą parametrów takich jak czas ostatniej aktualizacji.

Podobnie przy pobieraniu obrazów warto zmniejszyć ich rozmiar po stronie serwera, zamiast pobierać pełnowymiarowe obrazy, które są zmniejszone po stronie klienta.

Buforowanie odpowiedzi HTTP

Inną ważną metodą jest unikanie pobierania zduplikowanych danych. Korzystając z pamięci podręcznej, możesz zmniejszyć prawdopodobieństwo wielokrotnego pobierania tych samych danych. Dzięki buforowaniu danych i zasobów aplikacji tworzysz lokalną kopię informacji, do których aplikacja musi się odwoływać. Jeśli aplikacja musi wielokrotnie uzyskiwać dostęp do tych samych informacji w krótkim czasie, wystarczy, że pobierzesz ją do pamięci podręcznej tylko raz.

Ważne jest, aby intensywniej buforować dane w pamięci podręcznej, ponieważ pozwala to zmniejszyć całkowitą ilość pobieranych danych. Zawsze przechowuj w pamięci podręcznej zasoby statyczne, w tym pliki do pobrania na żądanie, takie jak obrazy w pełnym rozmiarze, tak długo, jak to możliwe. Zasoby na żądanie powinny być przechowywane oddzielnie, aby umożliwić regularne czyszczenie pamięci podręcznej na żądanie w celu zarządzania jej rozmiarem.

Aby mieć pewność, że buforowanie nie powoduje wyświetlania przez aplikację nieaktualnych danych, używaj odpowiednich kodów stanu i nagłówków HTTP, takich jak nagłówki ETag i Last-Modified. Dzięki temu możesz określić, kiedy powiązane treści mają zostać odświeżone. Na przykład:

Kotlin

// url represents the website containing the content to place into the cache.
val conn: HttpsURLConnection = url.openConnection() as HttpsURLConnection
val currentTime: Long = System.currentTimeMillis()
val lastModified: Long = conn.getHeaderFieldDate("Last-Modified", currentTime)

// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
    // Skip update
} else {
    // Parse update
    lastUpdateTime = lastModified
}

Java

// url represents the website containing the content to place into the cache.
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
long currentTime = System.currentTimeMillis();
long lastModified = conn.getHeaderFieldDate("Last-Modified", currentTime);

// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
    // Skip update
} else {
    // Parse update
    lastUpdateTime = lastModified;
}

Możesz skonfigurować niektóre biblioteki sieciowe tak, aby automatycznie respektowały te kody stanu i nagłówki. Jeśli na przykład korzystasz z OkHttp, skonfigurowanie katalogu pamięci podręcznej i rozmiaru pamięci podręcznej dla klienta spowoduje, że biblioteka będzie korzystać z pamięci podręcznej HTTP, jak pokazano w tym przykładowym kodzie:

Kotlin

val cacheDir = Context.getCacheDir()
val cacheSize = 10L * 1024L * 1024L // 10 MiB
val client: OkHttpClient = OkHttpClient.Builder()
    .cache(Cache(cacheDir, cacheSize))
    .build()

Java

File cacheDir = Context.getCacheDir();
long cacheSize = 10L * 1024L * 1024L; // 10 MiB
OkHttpClient client = new OkHttpClient.Builder()
    .cache(new Cache(cacheDir, cacheSize))
    .build();

Po skonfigurowaniu pamięci podręcznej możesz wysyłać żądania HTTP w pełni zapisane w pamięci podręcznej bezpośrednio z pamięci lokalnej, bez konieczności nawiązywania połączenia sieciowego. Warunkowo zapisywane odpowiedzi w pamięci podręcznej mogą sprawdzać aktualność danych z serwera, eliminując koszty przepustowości związane z pobieraniem. Niebuforowane odpowiedzi są przechowywane w pamięci podręcznej odpowiedzi na potrzeby przyszłych żądań.

Aby umieścić w pamięci podręcznej dane niewrażliwe w katalogu niezarządzanej zewnętrznej pamięci podręcznej, użyj narzędzia Context.getExternalCacheDir(). Możesz też zapisać dane w zarządzanej, bezpiecznej pamięci podręcznej aplikacji przy użyciu interfejsu Context.getCacheDir(). Pamiętaj, że wewnętrzna pamięć podręczna może zostać opróżniona, gdy w systemie zacznie brakować dostępnej pamięci.

Użyj repozytorium

Aby zastosować bardziej zaawansowane podejście do buforowania, rozważ wzorzec projektowy repozytorium. Wymaga to utworzenia klasy niestandardowej znanej jako repozytorium, która zapewnia abstrakcję interfejsu API dla określonych danych lub zasobów. Repozytorium może początkowo pobierać swoje dane z różnych źródeł, takich jak zdalna usługa internetowa, ale przy kolejnych wywołaniach udostępnia elementom wywołującym ich wersję z pamięci podręcznej. Ta warstwa pośrednia umożliwia zapewnienie solidnej strategii buforowania specyficznej dla Twojej aplikacji. Więcej informacji o korzystaniu ze wzorca repozytorium w aplikacji znajdziesz w Przewodniku po architekturze aplikacji.