При управлении жизненным циклом Android-приложения сохранение состояния пользователя во время высвобождения фоновых ресурсов является ключевым компонентом для обеспечения бесперебойной работы пользователя. Для приложений, использующих веб-процессы, WebView.saveState(Bundle) позволяет сериализовать историю навигации и состояние WebView в объект Bundle . Эти данные впоследствии можно восстановить с помощью WebView.restoreState(Bundle) .
Однако стандартные реализации могут столкнуться с ограничениями по размеру транзакций при интенсивной работе в браузере. На этой странице описываются эти архитектурные ограничения и предлагаются стратегии предотвращения исключений, связанных с памятью, при сохранении истории навигации.
Ограничение на транзакции в 1 МБ и удаление состояния
В Android действует строгое ограничение в 1 МБ на общий объем данных, которые могут храниться в savedInstanceState . Этот лимит в 1 МБ распределяется между всеми процессами приложения. Если приложение использует несколько экземпляров WebView , их общее состояние навигации и история должны укладываться в этот единый общий объем. Превышение этого предела вызывает исключение TransactionTooLargeException , что приводит к сбою приложения.
Распространенная, но проблемная стратегия смягчения последствий включает в себя мониторинг размера пакета состояния WebView и полную очистку истории WebView, если она превышает произвольный безопасный порог (например, 300 КБ). Хотя это предотвращает сбой, это приводит к серьезным ухудшениям пользовательского опыта:
Потеря возможности обратной навигации : Android часто завершает фоновые процессы приложений, чтобы освободить память для других задач. Вы можете использовать
saveState(Bundle)внутри функции обратного вызова жизненного циклаonSaveInstanceState()для сохранения истории навигации. Если вы удалите эту историю, чтобы избежать ограничения на транзакцию в 1 МБ, весь стек навигации будет потерян. Когда пользователь вернется в приложение, системная кнопка «Назад» немедленно завершит работу компонента или приложения, поскольку не останется исторического контекста для поддержки обратной навигации, независимо от того, был ли перезапущен процесс.Аннулирование BFCache : Очистка истории предотвращает использование приложением кэша «Вперед-назад» (BFCache), лишая возможности мгновенного отображения ранее посещенных страниц.
Увеличение задержки : пользователи теряют текущее состояние в WebView, что требует полной перенавигации и повторной инициализации. Этот процесс значительно увеличивает сетевую нагрузку и задержку транзакций.
Архитектурные стратегии смягчения последствий
Чтобы предотвратить сбои, вызванные ошибкой TransactionTooLargeException без ухудшения пользовательского опыта из-за полного удаления истории транзакций, необходимо поддерживать строгий баланс между сохранением состояния и эффективностью использования памяти. Внедрение следующих стратегий оптимизации позволит безопасно управлять бюджетом транзакций в 1 МБ, сохраняя при этом важную историю навигации и целостность сессии.
Вводить ограничения на размер сериализации состояния.
Вместо того чтобы полностью удалять стек навигации, когда он становится слишком большим, более эффективным подходом является усечение исторических данных:
Целенаправленная политика удаления : используйте
WebViewCompat.saveState()для сериализации состояния с соблюдением определенного ограничения по байтам (например,WebViewCompat.saveState(webView, outState, maxSizeBytes)). Этот API автоматически удаляет старые записи навигации последовательно, пока общий объем полезной нагрузки не поместится в заданное вами выделение памяти. Важно отметить, что это только обрезает сериализованныйBundle, не изменяя и не очищая историю активногоWebView, гарантируя, что немедленная обратная навигация останется полностью неизменной.Удаление записей навигации вперед : Если интерфейс приложения предоставляет кнопку «Назад», но не имеет отдельной кнопки навигации вперед, вы можете удалить все записи навигации вперед, установив параметр
includeForwardStateв APIsaveStateв значениеfalse. Это значительно уменьшает размер полезной нагрузки без влияния на доступные пользователю пути навигации.
Управляйте задержкой ресурсов с помощью API HTTP Cache Quota.
В то время как saveState управляет ограничением Bundle 1 МБ для временной истории навигации, API HTTP Cache Quota предоставляет возможность ручного управления постоянными веб-ресурсами (дисковым кэшем) для каждого профиля. Это создает четкое различие между краткосрочным контекстом навигации и долгосрочными кэшированными ресурсами.
Выбор подходящей квоты предполагает компромисс между производительностью и результатами:
- Увеличение квот улучшает доступность в автономном режиме и снижает задержку загрузки ресурсов за счет сохранения большего количества файлов на диске.
- Снижение квот минимизирует объем дискового пространства, занимаемого приложением, и предотвращает вытеснение других важных данных приложения из кэша операционной системы.
Эти настройки сохраняются после перезапуска приложения и должны быть сконфигурированы из основного потока.
Следующая реализация демонстрирует, как настроить квоту дискового кэша для профиля по умолчанию:
Котлин
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);
}
Для получения дополнительной информации о стратегиях определения размера квот, управлении жизненным циклом и границах профилей см. раздел «Управление квотой HTTP-кэша в WebView» .
Ключевые аспекты производительности
Следующие пункты освещают технические ограничения и внутренние особенности поведения данных, которые определяют состояние WebView:
Непрозрачные объекты
PageState: Примерно 70% данных, хранящихся вsaveStateсоставляют внутренние объектыPageStateиз механизма рендеринга. Эти данные фиксируют детальные состояния сессии, включая поля ввода форм и позиции прокрутки iframe. Избегайте попыток вручную анализировать или удалять отдельные сегменты из этих объектов, поскольку это создает серьезные риски безопасности и нарушает целостность восстановления сессии.Детальное управление историей : стандартный API
WebBackForwardListизначально не поддерживает произвольное удаление отдельных элементов истории. Для строгого управления состоянием необходимо реализовать стратегии усечения с использованием параметровmaxSizeBytesиincludeForwardStateвWebViewCompat.saveState()для обеспечения архитектурной безопасности.
При управлении жизненным циклом Android-приложения сохранение состояния пользователя во время высвобождения фоновых ресурсов является ключевым компонентом для обеспечения бесперебойной работы пользователя. Для приложений, использующих веб-процессы, WebView.saveState(Bundle) позволяет сериализовать историю навигации и состояние WebView в объект Bundle . Эти данные впоследствии можно восстановить с помощью WebView.restoreState(Bundle) .
Однако стандартные реализации могут столкнуться с ограничениями по размеру транзакций при интенсивной работе в браузере. На этой странице описываются эти архитектурные ограничения и предлагаются стратегии предотвращения исключений, связанных с памятью, при сохранении истории навигации.
Ограничение на транзакции в 1 МБ и удаление состояния
В Android действует строгое ограничение в 1 МБ на общий объем данных, которые могут храниться в savedInstanceState . Этот лимит в 1 МБ распределяется между всеми процессами приложения. Если приложение использует несколько экземпляров WebView , их общее состояние навигации и история должны укладываться в этот единый общий объем. Превышение этого предела вызывает исключение TransactionTooLargeException , что приводит к сбою приложения.
Распространенная, но проблемная стратегия смягчения последствий включает в себя мониторинг размера пакета состояния WebView и полную очистку истории WebView, если она превышает произвольный безопасный порог (например, 300 КБ). Хотя это предотвращает сбой, это приводит к серьезным ухудшениям пользовательского опыта:
Потеря возможности обратной навигации : Android часто завершает фоновые процессы приложений, чтобы освободить память для других задач. Вы можете использовать
saveState(Bundle)внутри функции обратного вызова жизненного циклаonSaveInstanceState()для сохранения истории навигации. Если вы удалите эту историю, чтобы избежать ограничения на транзакцию в 1 МБ, весь стек навигации будет потерян. Когда пользователь вернется в приложение, системная кнопка «Назад» немедленно завершит работу компонента или приложения, поскольку не останется исторического контекста для поддержки обратной навигации, независимо от того, был ли перезапущен процесс.Аннулирование BFCache : Очистка истории предотвращает использование приложением кэша «Вперед-назад» (BFCache), лишая возможности мгновенного отображения ранее посещенных страниц.
Увеличение задержки : пользователи теряют текущее состояние в WebView, что требует полной перенавигации и повторной инициализации. Этот процесс значительно увеличивает сетевую нагрузку и задержку транзакций.
Архитектурные стратегии смягчения последствий
Чтобы предотвратить сбои, вызванные ошибкой TransactionTooLargeException без ухудшения пользовательского опыта из-за полного удаления истории транзакций, необходимо поддерживать строгий баланс между сохранением состояния и эффективностью использования памяти. Внедрение следующих стратегий оптимизации позволит безопасно управлять бюджетом транзакций в 1 МБ, сохраняя при этом важную историю навигации и целостность сессии.
Вводить ограничения на размер сериализации состояния.
Вместо того чтобы полностью удалять стек навигации, когда он становится слишком большим, более эффективным подходом является усечение исторических данных:
Целенаправленная политика удаления : используйте
WebViewCompat.saveState()для сериализации состояния с соблюдением определенного ограничения по байтам (например,WebViewCompat.saveState(webView, outState, maxSizeBytes)). Этот API автоматически удаляет старые записи навигации последовательно, пока общий объем полезной нагрузки не поместится в заданное вами выделение памяти. Важно отметить, что это только обрезает сериализованныйBundle, не изменяя и не очищая историю активногоWebView, гарантируя, что немедленная обратная навигация останется полностью неизменной.Удаление записей навигации вперед : Если интерфейс приложения предоставляет кнопку «Назад», но не имеет отдельной кнопки навигации вперед, вы можете удалить все записи навигации вперед, установив параметр
includeForwardStateв APIsaveStateв значениеfalse. Это значительно уменьшает размер полезной нагрузки без влияния на доступные пользователю пути навигации.
Управляйте задержкой ресурсов с помощью API HTTP Cache Quota.
В то время как saveState управляет ограничением Bundle 1 МБ для временной истории навигации, API HTTP Cache Quota предоставляет возможность ручного управления постоянными веб-ресурсами (дисковым кэшем) для каждого профиля. Это создает четкое различие между краткосрочным контекстом навигации и долгосрочными кэшированными ресурсами.
Выбор подходящей квоты предполагает компромисс между производительностью и результатами:
- Увеличение квот улучшает доступность в автономном режиме и снижает задержку загрузки ресурсов за счет сохранения большего количества файлов на диске.
- Снижение квот минимизирует объем дискового пространства, занимаемого приложением, и предотвращает вытеснение других важных данных приложения из кэша операционной системы.
Эти настройки сохраняются после перезапуска приложения и должны быть сконфигурированы из основного потока.
Следующая реализация демонстрирует, как настроить квоту дискового кэша для профиля по умолчанию:
Котлин
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);
}
Для получения дополнительной информации о стратегиях определения размера квот, управлении жизненным циклом и границах профилей см. раздел «Управление квотой HTTP-кэша в WebView» .
Ключевые аспекты производительности
Следующие пункты освещают технические ограничения и внутренние особенности поведения данных, которые определяют состояние WebView:
Непрозрачные объекты
PageState: Примерно 70% данных, хранящихся вsaveStateсоставляют внутренние объектыPageStateиз механизма рендеринга. Эти данные фиксируют детальные состояния сессии, включая поля ввода форм и позиции прокрутки iframe. Избегайте попыток вручную анализировать или удалять отдельные сегменты из этих объектов, поскольку это создает серьезные риски безопасности и нарушает целостность восстановления сессии.Детальное управление историей : стандартный API
WebBackForwardListизначально не поддерживает произвольное удаление отдельных элементов истории. Для строгого управления состоянием необходимо реализовать стратегии усечения с использованием параметровmaxSizeBytesиincludeForwardStateвWebViewCompat.saveState()для обеспечения архитектурной безопасности.