Unikaj pobierania niezoptymalizowanych plików

Niektórzy użytkownicy Twojej aplikacji mają przerywany dostęp do internetu lub ograniczenia dotyczące ilości informacji, które mogą pobrać na swoje urządzenia. Możesz zachęcić użytkowników do częstszego korzystania z aplikacji, zmniejszając ilość danych, które musi ona pobrać.

Najprostszym sposobem na zmniejszenie liczby pobrań jest pobieranie tylko tego, czego potrzebujesz. W przypadku danych oznacza to wdrożenie interfejsów API REST, które umożliwiają określanie kryteriów zapytań ograniczających zwracane dane za pomocą parametrów takich jak czas ostatniej aktualizacji.

Podobnie podczas pobierania obrazów warto zmniejszyć ich rozmiar po stronie serwera, zamiast pobierać obrazy w pełnym rozmiarze i zmniejszać je po stronie klienta.

Buforowanie odpowiedzi HTTP

Kolejną ważną techniką jest unikanie pobierania zduplikowanych danych. Możesz zmniejszyć prawdopodobieństwo wielokrotnego pobierania tych samych danych, korzystając z pamięci podręcznej. Dzięki zapisywaniu w pamięci podręcznej danych i zasobów aplikacji tworzysz lokalną kopię informacji, do których aplikacja musi się odwoływać. Jeśli aplikacja musi uzyskać dostęp do tej samej informacji wiele razy w krótkim czasie, wystarczy pobrać ją do pamięci podręcznej tylko raz.

Aby zmniejszyć łączną ilość pobieranych danych, warto jak najczęściej korzystać z pamięci podręcznej. Zawsze zapisuj w pamięci podręcznej zasoby statyczne, w tym pobierane na żądanie pliki, takie jak obrazy w pełnym rozmiarze, tak długo, jak to możliwe. Zasoby na żądanie powinny być przechowywane oddzielnie, aby można było regularnie czyścić pamięć podręczną na żądanie i zarządzać jej rozmiarem.

Aby buforowanie nie powodowało wyświetlania w aplikacji nieaktualnych danych, używaj odpowiednich kodów stanu HTTP i nagłówków, takich jak nagłówki ETagLast-Modified. Dzięki temu możesz określić, kiedy powiązane treści powinny 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 uwzględniały te kody stanu i nagłówki. Na przykład podczas korzystania z OkHttp skonfigurowanie katalogu pamięci podręcznej i rozmiaru pamięci podręcznej dla klienta umożliwi bibliotece korzystanie 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 obsługiwać w pełni buforowane żądania HTTP bezpośrednio z pamięci lokalnej, eliminując konieczność otwierania połączenia sieciowego. Odpowiedzi buforowane warunkowo mogą sprawdzać swoją świeżość na serwerze, co eliminuje koszt przepustowości związany z pobieraniem. Odpowiedzi niepochodzące z pamięci podręcznej są w niej zapisywane na potrzeby przyszłych żądań.

Możesz przechowywać w pamięci podręcznej dane niewrażliwe w niezarządzanym zewnętrznym katalogu pamięci podręcznej, używając Context.getExternalCacheDir(). Możesz też przechowywać dane w zarządzanej, bezpiecznej pamięci podręcznej aplikacji, używając Context.getCacheDir(). Pamiętaj, że ta pamięć podręczna może zostać wyczyszczona, gdy w systemie zabraknie dostępnego miejsca na dane.

Korzystanie z repozytorium

Jeśli chcesz zastosować bardziej zaawansowane podejście do buforowania, rozważ użycie wzorca projektowego Repository. Wiąże się to z utworzeniem niestandardowej klasy, zwanej repozytorium, która zapewnia abstrakcję interfejsu API nad określonymi danymi lub zasobami. Repozytorium może początkowo pobierać dane z różnych źródeł, np. ze zdalnej usługi internetowej, ale w kolejnych wywołaniach udostępnia wywołującym je podmiotom wersję danych z pamięci podręcznej. Ta warstwa pośrednia umożliwia stosowanie niezawodnej strategii buforowania, która jest dostosowana do Twojej aplikacji. Więcej informacji o używaniu wzorca Repository w aplikacji znajdziesz w przewodniku po architekturze aplikacji.