Direct answer
A large local AI result should usually stay in app-owned durable storage while navigation and saved state carry a small, versioned result identifier. An Intent extra or SavedStateHandle is a transport for lightweight state, not a durable result database. If Android reports TransactionTooLargeException, the transaction failed, but the exception does not tell the caller whether the request failed before the remote side handled it or whether the response failed on its way back. Treat that as a partial-failure boundary: look up the same operation identifier with its owner before deciding whether to attach, show a completed result, or offer a bounded retry. Android documents a currently 1 MB Binder transaction buffer shared by transactions in progress for a process. That is not a safe per-call payload allowance: concurrent transactions consume the shared capacity, and the exact serialized transaction has more than the model text alone. Do not size a generated answer, image, transcript, or document summary to a guessed fraction of that number. Android also recommends keeping saved state small; the less-than-50-KB guidance applies specifically to rememberSaveable, not as a universal Intent, Bundle, or Binder limit. The class TransactionTooLargeException exists from API 15, while the platform documentation describes it being thrown as a runtime exception on Android 7.0/API 24 and later. Do not assume identical observable exception behavior on every older release or every system path. Start by identifying the actual boundary. A large value may be in an activity launch Intent, a fragment or navigation argument, rememberSaveable or SavedStateHandle state, a service call, or another IPC. These paths can serialize overlapping state and compete with unrelated Binder work. Reproduce with a synthetic result and record the Android version, lifecycle action, transaction path, result size, and exception site. Parcel.dataSize() can report the data contained in a Parcel built for a controlled diagnostic fixture. It is useful evidence about that Parcel, not a measurement of all in-flight transactions, system bookkeeping, competing calls, or a guaranteed pass threshold. Never persist a raw Parcel or its marshalled bytes as the result format. For a result that must survive navigation or process death, persist ordinary application data first: a file, database row, or other bounded store with an operation ID, result revision, schema/version, owner, state, and expiry policy. Confirm the write before passing the short ID. At the destination, check that the current user and component are authorized to read that ID, that its revision and state are still valid, and that its retention window has not expired. An ID locates a record; it is not authorization. If the result itself is not durable by product design, say so and return an explicit unavailable or regenerate choice instead of passing a stale pointer. Retry needs the same care as storage. A TransactionTooLargeException can leave completion uncertain, so retrying a model request can waste time or replace a newer answer; retrying a downstream action can duplicate an external or persistent effect. Query the operation owner using the same operation ID and request revision. If the owner confirms a completed record, read it. If it confirms work is still active, observe that operation rather than launch another. Retry only after the owner confirms that the prior attempt has terminated without committing, or when the same ID reaches an owner-side atomic or serialized deduplication boundary that enforces idempotency. A missing record is not proof of no commit: the work may still be running or its acknowledgement may have failed. Keep the state unknown until the owner can resolve it. A locally generated ID alone provides no at-most-once guarantee. When another component or app needs the result bytes, use a deliberately scoped file-sharing contract rather than a filesystem path. Android recommends content URIs with narrowly granted access for file handoff; temporary grants have a lifecycle and can expire when the receiving task stack finishes. A content URI string alone is only a locator, not authorization: the provider must permit access and the recipient must hold the actual applicable URI grant. Default to read-only; grant write access only for an explicit, necessary edit workflow that the user and provider allow. Verify recipient, scope, provider behavior, grant lifetime, and cleanup policy. Close file descriptors after use. Descriptor leaks are a separate resource-lifecycle diagnosis; switching to a URI does not prove descriptors are closed, and a descriptor leak is not the explanation for every oversized transaction. Keep this topic separate from parsing model output. JSON syntax, schema validation, partial generations, and semantic checks happen after bytes reach the receiving code; they neither measure Binder capacity nor establish whether an IPC request ran. Likewise, general process-recreation design already calls for lightweight saved IDs and reconstructing runtime state. This guide narrows the question to oversized local-result handoffs and uncertain transaction completion. It describes Android boundaries and a validation method, not a Cove Binder service, a known Cove crash, or an implemented result store.
A generated report disappears during navigation
A prototype generates a long local report, places the full text in navigation state, and opens a review screen. The transition sometimes raises TransactionTooLargeException, while a retry button may start the same inference again even though the first operation may have completed.
Decision
Keep the generated bytes in a bounded app-owned result store, pass a short result ID, and make the receiving screen query the task owner before offering any retry.
Expected outcome
The review screen shows the saved result, an active operation, or an honest unavailable state without assuming the exception identifies which side failed or duplicating work.
Evidence to collect
The claim becomes reviewable only when the following evidence is attached to the same artifact and test run:
- Actual handoff path and controlled Parcel size
- Persisted result identity and bounded metadata
- Unknown-outcome and owner-deduplicated retry fixtures
A device badge must come from an exact device, OS, artifact, runtime, backend, and workload record, not parameter-count intuition.
Implementation workflow
- Map and reproduce the transaction boundary. Trace where the result crosses a framework boundary: activity Intent, navigation or fragment arguments, saved-state Bundle, service call, or another IPC. Use a synthetic result with controlled sizes and reproduce navigation, backgrounding, and recreation separately. Record OS/API level, transaction path, exception location, and concurrent activity; do not infer a universal safe byte ceiling from one passing sample.
- Measure only the serialized fixture you can observe. Where a controlled Parcel fixture matches the relevant encoder, record Parcel.dataSize() as diagnostic serialized-byte evidence. Label the fixture and wrapper. It excludes other in-flight process transactions and does not certify system overhead, the complete Binder transaction, or a guaranteed threshold. Keep measurement fixtures synthetic and never persist raw Parcel objects or marshalled Parcel bytes as application data.
- Persist the result before transferring a reference. Write ordinary result bytes or structured application data to the intended repository first. Store an operation ID, revision, schema version, owner, state, and expiry/cleanup policy with it. Verify the write and authorization check before passing a small ID; if persistence fails, keep the result visible in its current owner and expose a truthful retry or export path.
- Resolve partial failure through the operation owner. On TransactionTooLargeException, do not assume the handler did not run. Query the same operation ID and revision: load committed output, observe in-progress work, or retry only after the owner confirms the prior attempt terminated without committing, or the same ID reaches an owner-side atomic/serialized deduplication boundary. A missing record may mean the work is still running or its acknowledgement failed; keep the state unknown if the owner cannot resolve it. Bound retries and never mint a fresh ID just to bypass uncertainty.
- Use a URI contract only when bytes must cross components. For a file handoff, provide a content URI from an appropriate provider and grant only the required temporary permission through the documented Intent mechanism; default to read-only and allow write only for an explicit necessary edit flow. The URI string alone is a locator, not authorization: provider policy and the actual grant must permit this recipient to open it. Test expiry and revocation, and close every opened descriptor. A record ID is lookup metadata, and a filesystem path alone is neither a cross-app contract nor a grant.
- Test recovery, retention, and cleanup independently. Inject failure before persistence, after persistence but before navigation, at the transaction boundary, after the receiving side reads the ID, and during retry. Check that result revisions do not overwrite one another, expired records are removed under policy, URI access ends as expected, descriptors close, and duplicate side effects are rejected by the operation owner rather than assumed away by local UI state.
Keep each transition observable. A failure should identify the stage, artifact, runtime, and recovery action without logging private user content.
Acceptance criteria
- The saved-state and Intent payloads contain only bounded navigation metadata; generated result bytes remain in the declared result owner until a verified cleanup event.
- A synthetic Parcel size observation is labeled as fixture evidence, never as a per-call Binder limit or proof that competing process transactions cannot cause failure.
- An exception leaves the operation in a recoverable unknown state until the owner resolves the same operation ID; retry requires terminal no-commit confirmation or enforced owner-side atomic/serialized idempotency, and duplicate side effects are rejected.
- Any file handoff uses a tested content URI plus provider permission and an actual least-privilege grant, defaults to read-only, and documents lifetime; the URI string alone is not authorization.
Decision table
| Dimension | Choice or evidence | How to interpret it |
|---|---|---|
| Full result in Intent or saved state | Serialize the complete text or object graph at each transition | Simple for small transient values, but size and serialization cost grow with result complexity and shared transaction load; unsuitable as the default for large generated output. |
| Durable result plus stable ID | Persist ordinary data and pass a short operation/result reference | Keeps navigation bounded and allows owner-side status lookup after ambiguous failure; requires explicit authorization, version, expiry, and cleanup checks. |
| Content URI for file bytes | Expose a provider-backed resource with an Intent URI grant | Appropriate when another component needs file access, but the URI string alone grants nothing: provider access and the actual scoped grant must both permit it. Default to read-only and test grant lifetime. |
| Split data into many Binder calls | Chunk a large payload across transactions | May fit a deliberately designed streaming protocol, but adds ordering, partial-write, retry, and cleanup states; it is not a substitute for durable ownership when the result must survive lifecycle changes. |
Failure patterns to prevent
- Treating shared Binder capacity as a per-call allowance
- Retrying uncertain operations under a fresh ID
- Treating a URI string or result ID as authorization
Also prevent silent fallback, unpinned artifacts, missing cancellation, and conclusions that combine unlike configurations. Store unsuccessful runs alongside successful ones.
Minimum reproducibility record
| Layer | Record |
|---|---|
| Device | Manufacturer, model, chipset, RAM class, operating-system build |
| Software | Application version and git commit |
| Model | Family, variant, revision, format, file length, hash, quantization |
| Runtime | Name, revision, requested backend, observed backend evidence |
| Workload | Fixture revision, input hash, prompt hash, output policy |
| Outcome | Completed, failed, cancelled, fallback, and privacy-safe diagnostics |
Release checklist
- ☐ The primary query is answered without an unsupported number.
- ☐ Every artifact and runtime is pinned.
- ☐ The representative task and failure policy are explicit.
- ☐ Lifecycle, cancellation, cleanup, and fallback are tested.
- ☐ User-content and network boundaries are documented.
- ☐ Result wording applies only to the recorded configuration.
- ☐ The page links to raw method or evidence when results are added.
Sources and related evidence
- Android Developers — TransactionTooLargeException
- Android Developers — Parcel.dataSize()
- Android Developers — Parcelables and bundles
- Android Developers — Save UI states
- Android Developers — Secure file sharing
Chinese deployment and troubleshooting content is organized in the .奇连 AI 端侧专题.
Frequently asked questions
Is 1 MB the maximum payload for every Android Intent?
No. Android describes a 1 MB Binder buffer shared by transactions in progress for a process, not a dependable per-Intent allowance. Concurrent transactions and serialization overhead matter, so keep payloads small and verify the actual handoff path.
Does TransactionTooLargeException tell me whether inference ran?
No. Android documents that the request may not have reached the service, or the response may have failed to return, and the caller cannot distinguish those outcomes from the exception alone. Query the same operation owner before retrying.
Can Parcel.dataSize() prove a handoff will succeed?
No. It reports bytes contained in that Parcel fixture. It does not account for other concurrent Binder transactions or certify a system transaction threshold. Use it as comparative diagnostic evidence, not a compatibility guarantee.
Is passing a result ID enough to let another component read it?
No. The ID is only a locator, and a content URI string is also only a locator. The result owner must authorize an ID lookup; file access requires a provider that permits it and an actual scoped URI grant. Default to read-only and test expiry.
Should I retry immediately when a navigation transaction fails?
Not blindly. A response-side failure can occur after the owner handled the request, and a missing record may still be in progress. Retry only after the owner confirms terminal no-commit, or when same-ID retries pass through an atomic/serialized owner-side deduplication boundary; otherwise keep the outcome unknown.