When managing an Android app's lifecycle, preserving user state during
background resource reclamation is a core component of a seamless user
experience. For apps incorporating web workflows, WebView.saveState(Bundle)
lets you serialize a WebView's navigation history and state into a Bundle.
This data can subsequently be restored using WebView.restoreState(Bundle).
However, standard implementations can run into transaction size limitations under heavy browsing sessions. This page describes these architectural limitations and provides strategies to prevent memory-related exceptions while maintaining navigation history.
The 1MB transaction limit and state wiping
Android imposes a strict 1MB limit on the total volume of data that can be
stored within savedInstanceState. This 1MB budget is shared across the entire
app process. If an app incorporates multiple WebView instances, their
collective navigation state and history must fit within this single shared
allocation. Exceeding this boundary triggers a TransactionTooLargeException,
resulting in an app crash.
A common but problematic mitigation strategy involves monitoring the size of the WebView state bundle and completely clearing the WebView history if it crosses an arbitrary safety threshold (such as 300KB). While this prevents a crash, it introduces severe regressions into the user experience:
Loss of backward navigation: Android often terminates background app processes to reclaim memory for other tasks. You can use
saveState(Bundle)within theonSaveInstanceState()lifecycle callback to preserve navigation history. If you wipe this history to avoid the 1MB transaction limit, the entire navigation stack is lost. When the user returns to the app, the system back button immediately exits the component or app because no historical context remains to support backward navigation, regardless of whether a process restart occurred.BFCache invalidation: Clearing history prevents the app from using the Back-Forward Cache (BFCache), removing the ability to instantly render previously visited pages.
Increased latency: Users lose their current state within the WebView, requiring full re-navigation and re-initialization. This process significantly increases network overhead and transaction latency.
Architectural mitigation strategies
To prevent TransactionTooLargeException crashes without degrading the
user experience through complete history deletion, you must maintain a rigorous
balance between state retention and memory efficiency. By implementing the
following optimization strategies, you can safely manage the 1MB transaction
budget while preserving essential navigation history and session integrity.
Enforce size limits on state serialization
Instead of completely wiping the navigation stack when it grows too large, a more effective pattern is to truncate the historical data:
Targeted drop policy: Use
WebViewCompat.saveState()to serialize state while enforcing a specific byte limit (for example,WebViewCompat.saveState(webView, outState, maxSizeBytes)). This API automatically drops older navigation entries sequentially until the total payload fits within your defined allocation. Crucially, this only truncates the serializedBundlewithout modifying or clearing the live history of the activeWebView, ensuring immediate backward navigation remains completely intact.Forward entry removal: If the application interface provides a back button but lacks a dedicated forward navigation button, you can discard all forward navigation entries by setting the
saveStateAPI'sincludeForwardStateparameter tofalse. This significantly reduces the payload size without impacting the user's available navigation paths.
Manage resource latency with the HTTP Cache Quota API
While saveState manages the 1MB Bundle limit for ephemeral navigation
history, the HTTP Cache Quota API provides manual control over persisted web
resources (disk cache) on a per-profile basis. This creates a clear distinction
between short-term navigation context and long-term cached assets.
Choosing an appropriate quota involves a performance trade-off:
- Higher quotas improve offline availability and resource loading latency by keeping more assets on disk.
- Lower quotas minimize the app's disk footprint and prevent OS-led cache eviction of other critical app data.
These settings are persisted across app restarts and must be configured from the main thread.
The following implementation demonstrates how to configure a disk cache quota for the default profile:
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);
}
For more information about quota sizing strategies, lifecycle management, and profile boundaries, see Manage HTTP cache quota in WebView.
Key performance considerations
The following points highlight the technical limitations and internal data behaviors that govern WebView state behavior:
Opaque
PageStateblobs: Approximately 70% of the data stored bysaveStateconsists of internalPageStateblobs from the rendering engine. This data captures granular session states, including form inputs and iframe scroll positions. Avoid attempting to manually parse or strip individual segments from these blobs, as doing so poses severe security risks and breaks session restoration integrity.Granular history management: The standard
WebBackForwardListAPI doesn't natively support the arbitrary removal of individual historical elements. For strict state management, you must implement truncation strategies using themaxSizeBytesandincludeForwardStateparameters withinWebViewCompat.saveState()to ensure architectural safety.