Podczas zarządzania cyklem życia aplikacji na Androida zachowanie stanu użytkownika podczas odzyskiwania zasobów w tle jest podstawowym elementem zapewniającym spójne wrażenia użytkownika. W przypadku aplikacji korzystających z przepływów pracy w internecie funkcja WebView.saveState(Bundle)
umożliwia serializowanie historii nawigacji i stanu komponentu WebView do obiektu Bundle.
Te dane można później przywrócić za pomocą funkcji WebView.restoreState(Bundle).
Jednak w przypadku standardowych implementacji podczas intensywnych sesji przeglądania mogą wystąpić ograniczenia rozmiaru transakcji. Na tej stronie opisujemy te ograniczenia architektoniczne i przedstawiamy strategie zapobiegania wyjątkom związanym z pamięcią przy jednoczesnym zachowaniu historii nawigacji.
Limit transakcji wynoszący 1 MB i czyszczenie stanu
Android nakłada ścisły limit 1 MB na łączną ilość danych, które można przechowywać w savedInstanceState. Ten limit 1 MB jest wspólny dla całego procesu aplikacji. Jeśli aplikacja zawiera kilka instancji WebView, ich łączny stan nawigacji i historia muszą mieścić się w tym jednym wspólnym przydziale. Przekroczenie tego limitu powoduje wywołanie wyjątku TransactionTooLargeException, co prowadzi do awarii aplikacji.
Powszechna, ale problematyczna strategia ograniczania ryzyka polega na monitorowaniu rozmiaru pakietu stanu WebView i całkowitym czyszczeniu historii WebView, jeśli przekroczy ona arbitralny próg bezpieczeństwa (np. 300 KB). Chociaż zapobiega to awarii, powoduje poważne regresje w zakresie wrażeń użytkownika:
Utrata nawigacji wstecz: Android często zamyka procesy aplikacji działające w tle , aby odzyskać pamięć na potrzeby innych zadań. Aby zachować historię nawigacji, możesz użyć funkcji
saveState(Bundle)w wywołaniu zwrotnym cyklu życiaonSaveInstanceState(). Jeśli wyczyścisz tę historię, aby uniknąć limitu transakcji wynoszącego 1 MB, utracisz cały stos nawigacji. Gdy użytkownik wróci do aplikacji, systemowy przycisk Wstecz natychmiast zamknie komponent lub aplikację, ponieważ nie ma już kontekstu historycznego, który umożliwiałby nawigację wstecz, niezależnie od tego, czy nastąpiło ponowne uruchomienie procesu.Unieważnienie pamięci podręcznej BFCache: wyczyszczenie historii uniemożliwia aplikacji korzystanie z pamięci podręcznej stanu strony internetowej (BFCache), co uniemożliwia natychmiastowe renderowanie wcześniej odwiedzonych stron.
Zwiększone opóźnienie: użytkownicy tracą bieżący stan w komponencie WebView, co wymaga pełnej ponownej nawigacji i ponownej inicjalizacji. Ten proces znacznie zwiększa obciążenie sieci i opóźnienie transakcji.
Architektoniczne strategie ograniczania ryzyka
Aby zapobiec awariom spowodowanym przez wyjątek TransactionTooLargeException bez pogorszenia wrażeń
użytkownika przez całkowite usunięcie historii, musisz zachować równowagę
między zachowaniem stanu a wydajnością pamięci. Wdrażając te strategie optymalizacji, możesz bezpiecznie zarządzać limitem transakcji wynoszącym 1 MB, zachowując przy tym niezbędną historię nawigacji i integralność sesji.
Wymuszanie limitów rozmiaru serializacji stanu
Zamiast całkowicie czyścić stos nawigacji, gdy stanie się zbyt duży, skuteczniejszym rozwiązaniem jest obcięcie danych historycznych:
Zasada ukierunkowanego usuwania: użyj funkcji
WebViewCompat.saveState(), aby serializować stan, jednocześnie wymuszając określony limit bajtów (np.WebViewCompat.saveState(webView, outState, maxSizeBytes)). Ten interfejs API automatycznie usuwa starsze wpisy nawigacji kolejno, aż łączna ilość danych zmieści się w zdefiniowanym przydziale. Co najważniejsze, powoduje to tylko obcięcie serializowanego obiektuBundlebez modyfikowania ani czyszczenia historii aktywnego komponentuWebView, co zapewnia, że natychmiastowa nawigacja wstecz pozostanie w pełni nienaruszona.Usuwanie wpisów do przodu: jeśli interfejs aplikacji zawiera przycisk Wstecz ale nie ma przycisku nawigacyjnego Dalej, możesz odrzucić wszystkie wpisy nawigacji do przodu, ustawiając parametr
saveStateinterfejsu APIincludeForwardStatenafalse. Znacznie zmniejsza to rozmiar danych bez wpływu na dostępne ścieżki nawigacji użytkownika.
Zarządzanie opóźnieniem zasobów za pomocą interfejsu HTTP Cache Quota API
Funkcja saveState zarządza limitem 1 MB Bundle dla tymczasowej historii nawigacji, a interfejs HTTP Cache Quota API umożliwia ręczne sterowanie utrwalonymi zasobami internetowymi (pamięcią podręczną dysku) w ramach poszczególnych profili. Pozwala to wyraźnie odróżnić krótkoterminowy kontekst nawigacji od długoterminowych zasobów przechowywanych w pamięci podręcznej.
Wybór odpowiedniego limitu wiąże się z kompromisem w zakresie wydajności:
- Wyższe limity zwiększają dostępność offline i zmniejszają opóźnienie wczytywania zasobów, ponieważ więcej zasobów jest przechowywanych na dysku.
- Niższe limity minimalizują rozmiar aplikacji na dysku i zapobiegają usuwaniu z pamięci podręcznej innych ważnych danych aplikacji przez system operacyjny.
Te ustawienia są zachowywane po ponownym uruchomieniu aplikacji i muszą być skonfigurowane w wątku głównym.
Poniższa implementacja pokazuje, jak skonfigurować limit pamięci podręcznej dysku dla profilu domyślnego:
Kotlin
if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROFILE) &&
WebViewFeature.isFeatureSupported(WebViewFeature.HTTP_CACHE)) {
val defaultProfile = ProfileStore.getInstance()
.getOrCreateProfile(Profile.DEFAULT_PROFILE_NAME)
val httpCache = defaultProfile.httpCache
// Set explicit cache size to 50MB (50 * 1024 * 1024 bytes)
httpCache.setQuotaBytes(50L * 1024 * 1024)
}
Java
if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROFILE) &&
WebViewFeature.isFeatureSupported(WebViewFeature.HTTP_CACHE)) {
Profile defaultProfile = ProfileStore.getInstance()
.getOrCreateProfile(Profile.DEFAULT_PROFILE_NAME);
HttpCache httpCache = defaultProfile.getHttpCache();
// Set explicit cache size to 50MB (50 * 1024 * 1024 bytes)
httpCache.setQuotaBytes(50L * 1024 * 1024);
}
Więcej informacji o strategiach określania rozmiaru limitu, zarządzaniu cyklem życia i granicach profilu znajdziesz w artykule Zarządzanie limitem pamięci podręcznej HTTP w komponencie WebView.
Najważniejsze kwestie dotyczące wydajności
Poniższe punkty podkreślają ograniczenia techniczne i wewnętrzne zachowania danych, które określają zachowanie stanu komponentu WebView:
Nieprzezroczyste
PageStateobiekty blob: około 70% danych przechowywanych przezsaveStateto wewnętrznePageStateobiekty blob z silnika renderowania. Te dane rejestrują szczegółowe stany sesji, w tym dane wpisane w formularzach i pozycje przewijania w elementach iframe. Nie próbuj ręcznie analizować ani usuwać poszczególnych segmentów z tych obiektów blob, ponieważ stwarza to poważne zagrożenia dla bezpieczeństwa i narusza integralność przywracania sesji.Szczegółowe zarządzanie historią: standardowy interfejs API
WebBackForwardListnie obsługuje natywnie dowolnego usuwania poszczególnych elementów historycznych. Aby zapewnić ścisłe zarządzanie stanem, musisz wdrożyć strategie obcinania danych za pomocą parametrówmaxSizeBytesiincludeForwardStatew funkcjiWebViewCompat.saveState(), aby zapewnić bezpieczeństwo architektury.