Unikaj pobierania niezoptymalizowanych plików

Niektórzy użytkownicy Twojej aplikacji mają przerywany dostęp do internetu lub ograniczoną ilość 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 ograniczenie liczby pobrań jest pobieranie tylko tego, czego potrzebujesz. W przypadku danych oznacza to implementację interfejsów API REST, które umożliwiają określenie kryteriów zapytania ograniczających zwracane dane za pomocą parametrów takich jak czas ostatniej aktualizacji.

Podobnie w przypadku pobierania obrazów warto zmniejszyć ich rozmiar po stronie serwera, zamiast pobierać obrazy w pełnym rozmiarze, które są zmniejszane po stronie klienta.

Zapisywanie odpowiedzi HTTP w pamięci podręcznej

Inną ważną techniką jest unikanie pobierania duplikatów danych. Możesz zmniejszyć prawdopodobieństwo wielokrotnego pobierania tych samych danych, korzystając z pamięci podręcznej. Przechowując dane i zasoby aplikacji w pamięci podręcznej, tworzysz lokalną kopię informacji, do których aplikacja musi się odwoływać. Jeśli aplikacja musi uzyskać dostęp do tego samego elementu informacji kilka razy w krótkim czasie, musisz pobrać go do pamięci podręcznej tylko raz.

Ważne jest, aby jak najwięcej danych było przechowywane w pamięci podręcznej, ponieważ zmniejsza to łączną ilość pobieranych danych. Zawsze przechowuj w pamięci podręcznej zasoby statyczne, w tym zasoby do pobrania na żądanie, takie jak obrazy w pełnej rozdzielczości, tak długo, jak to możliwe. Zasoby na żądanie powinny być przechowywane osobno, aby umożliwić regularne czyszczenie pamięci podręcznej na żądanie i zarządzanie jej rozmiarem.

Aby mieć pewność, że buforowanie nie spowoduje wyświetlania przez aplikację nieaktualnych danych, używaj odpowiednich kodów stanu i nagłówków HTTP, takich jak nagłówki ETagLast-Modified. Dzięki temu możesz określić, kiedy powiązane treści powinny zostać odświeżone. 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;
}

Niektóre biblioteki sieciowe możesz skonfigurować tak, aby automatycznie uwzględniały te kody stanu i nagłówki. Jeśli używasz na przykład OkHttp, skonfigurowanie katalogu pamięci podręcznej i jej rozmiaru dla klienta umożliwi bibliotece korzystanie z pamięci podręcznej HTTP, jak pokazano w tym przykładzie kodu:

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ć żądania HTTP w pełnym zakresie z pamięci podręcznej, co eliminuje konieczność otwierania połączenia sieciowego. Odpowiedzi z warunkowym buforowaniem mogą być weryfikowane pod kątem aktualności przez serwer, co eliminuje koszty przepustowości związane z pobieraniem. Odpowiedzi nieprzechowywane w pamięci podręcznej są przechowywane w pamięci podręcznej odpowiedzi na potrzeby przyszłych żądań.

Dane niepoufne możesz zapisać w pamięci podręcznej w niezarządzanym katalogu pamięci podręcznej zewnętrznej, używając Context.getExternalCacheDir(). Możesz też zapisać dane w zarządzanej, zabezpieczonej pamięci podręcznej aplikacji, używającContext.getCacheDir(). Pamiętaj, że ta wewnętrzna pamięć podręczna może zostać wyczyszczona, gdy systemowi zabraknie dostępnej pamięci.

Korzystanie z repozytorium

Jeśli chcesz zastosować bardziej zaawansowane podejście do buforowania, rozważ użycie wzorca Repository. Polega to na utworzeniu niestandardowej klasy zwanej repozytorium, która zapewnia abstrakcję interfejsu API dla określonych danych lub zasobów. Repozytorium może początkowo pobierać dane z różnych źródeł, takich jak zdalna usługa internetowa, ale w kolejnych wywołaniach przekazuje wywołującym wersję danych z pamięci podręcznej. Ten warstwowy pośrednik umożliwia stosowanie skutecznej strategii buforowania, która jest dostosowana do Twojej aplikacji. Więcej informacji o używaniu w aplikacji wzorca repozytorium znajdziesz w przewodniku po architekturze aplikacji.