直接回答
大型本地 AI 结果通常应保存在应用所有者管理的持久存储中,而导航与保存状态只携带短小、带版本的结果标识。Intent extra 或 SavedStateHandle 是轻量状态传递机制,不是结果数据库。如果 Android 报告 TransactionTooLargeException,事务失败了,但异常不能告诉调用方:究竟是请求在远端处理前未送达,还是远端已经处理、只是响应未能返回。应把它视为部分失败边界:先用同一操作标识查询所有者,再决定读取已完成结果、观察正在进行的任务,或提供有限重试。 Android 文档称 Binder 当前有 1 MB 的事务缓冲,并由该进程正在进行的事务共享。这不是单次调用的安全载荷额度:并发事务会占用共享容量,实际序列化事务也不只有模型文本本身。不要把生成答案、图片、转写或文档摘要限制在对这个数字猜出来的某个比例。Android 也建议保存状态保持精简;小于 50 KB 的建议仅针对 rememberSaveable,不能当作 Intent、Bundle 或 Binder 的通用限额。TransactionTooLargeException 类自 API 15 存在,但平台文档说明 Android 7.0/API 24 及以上会将其作为运行时异常抛出。不能假设更早系统或所有系统调用路径都呈现相同异常行为。 第一步是识别真正的边界。大值可能位于 Activity 启动 Intent、Fragment 或导航参数、rememberSaveable / SavedStateHandle、Service 调用或其他 IPC 中。这些路径可能序列化重叠状态,并与其他 Binder 工作竞争。用合成结果复现,记录 Android 版本、生命周期动作、交易路径、结果大小和异常位置。Parcel.dataSize() 可报告为受控诊断夹具构造的 Parcel 所含数据量;它只是该 Parcel 的字节证据,不是所有在途交易、系统 bookkeeping、竞争调用或保证通过阈值的测量。绝不能把原始 Parcel 或其编组字节当成结果格式持久化。 若结果需要跨导航或进程死亡保留,先写入普通应用数据:文件、数据库行或其他有界存储,并记录操作 ID、结果修订、schema/版本、所有者、状态和过期策略。确认写入成功后才传递短 ID。目标页面要检查当前用户和组件是否有权读取该 ID,修订与状态是否仍有效,以及保留期是否到期。ID 用于定位记录,并不等于授权。如果产品设计不保证结果持久存在,应明确显示不可用或重新生成选择,而不是传递过期指针。 重试也需要同样谨慎。TransactionTooLargeException 会让完成情况不确定,因此重试模型请求可能浪费时间或覆盖较新答案;重试下游动作可能重复外部或持久副作用。用相同操作 ID 和请求修订查询所有者:若已完成则读取;若仍在处理则观察原任务。只有所有者确认旧尝试已终止且未提交,或相同 ID 进入所有者端原子/串行去重边界并强制执行幂等规则时,才可重试。查不到记录不代表未提交:任务可能仍在运行,或回执丢失。所有者无法解决前,应保持未知状态。本地生成一个 ID 本身不提供“最多一次”保证。 如果另一个组件或应用需要结果字节,应使用有明确范围的文件共享合同,而不是文件系统路径。Android 推荐通过 content URI 和范围明确的授权来交接文件;临时授权有生命周期,接收方任务栈结束时可能过期。content URI 字符串本身只是定位符,不是授权:Provider 必须允许访问,接收方还必须持有实际适用的 URI grant。默认只读;只有存在明确且必要、并获用户与 Provider 允许的编辑流程时才授予写权限。要验证接收方、权限范围、Provider 行为、授权期限和清理策略。使用后关闭文件描述符。描述符泄漏是独立的资源生命周期诊断;改用 URI 不证明描述符一定关闭,描述符泄漏也不是所有大交易失败的原因。 这个主题也要与模型输出解析分开。JSON 语法、schema 校验、部分生成和语义检查发生在接收代码拿到字节之后;它们既不测量 Binder 容量,也无法证明 IPC 请求是否执行。同样,一般进程恢复设计已经要求保存轻量 ID 并重建运行时状态。本文只收窄到大型本地结果交接和交易完成不确定性的处理。它描述 Android 边界与验证方法,不声称 Cove 有 Binder 服务、发生过相关崩溃或已经实现结果存储。
导航时生成的报告消失
原型生成一篇较长的本地报告,把全文放入导航状态后打开审核页面。页面切换偶尔抛出 TransactionTooLargeException,而重试按钮可能重新启动同一推理,即使第一次操作其实已经完成。
决策
把生成字节写入有界且由应用所有者管理的结果存储,传递短结果 ID,并让目标页面先查询任务所有者再提供重试。
预期结果
审核页面能显示已保存结果、正在进行的任务或诚实的不可用状态;不会假设异常指出了哪一端失败,也不会重复执行工作。
需要收集的证据
只有将以下证据与同一模型文件和测试运行关联起来,结论才可复核:
- ANDROID-BINDER-RESULT-HANDOFF-2026-10:共享缓冲、异常完成不确定性及 Parcel 字节观测均由官方 API 与状态文档限定,不是 Cove 功能证明。
- MEMORY-01:峰值推理内存还受运行时缓冲、KV cache、输入张量、系统余量和分配器影响;模型输出字节数不是系统交易容量结论。
- COVE-LIFECYCLE-01:当前 Cove ModelManager 有明确模型状态与加载所有权;这不证明产品有 Binder 结果服务或已出现相关事故。
- Android 官方 TransactionTooLargeException 与 Parcel API 定义事务共享缓冲和 Parcel 字节观测边界。
设备兼容结论须绑定具体设备、系统、模型、运行时、后端和工作负载,不能靠参数量推测。
实施流程
- 定位并复现交易边界. 追踪结果越过的框架边界:Activity Intent、导航或 Fragment 参数、saved-state Bundle、Service 调用或其他 IPC。使用大小受控的合成结果,分别复现导航、后台切换和进程重建;记录系统/API 版本、交易路径、异常位置和并发活动,不从一个成功样本推导通用安全字节上限。
- 只测量可观察到的序列化夹具. 若受控 Parcel 夹具与实际编码器一致,可记录 Parcel.dataSize() 作为序列化字节诊断,并标明夹具和包装方式。它不包含进程内其他在途 Binder 事务,也不能认证系统开销、完整 Binder 交易或保证通过的阈值。测量只用合成数据,不能把原始 Parcel 对象或编组后的 Parcel 字节持久化为应用数据。
- 先保存结果再传递引用. 先把普通结果字节或结构化应用数据写入预定 Repository,附带操作 ID、修订号、schema 版本、所有者、状态和到期/清理策略。确认写入成功并通过授权检查后再传短 ID;若写入失败,就在当前所有者处保留结果,并展示诚实的重试或导出路径。
- 通过操作所有者处理部分失败. 出现 TransactionTooLargeException 时,不要假设处理器没运行。用同一个操作 ID 和修订号查询:读取已提交输出、观察仍在运行的任务;只有所有者确认旧尝试已终止且未提交,或相同 ID 进入所有者端原子/串行去重边界时才重试。查不到记录可能表示任务仍在运行或回执丢失;所有者无法解决时保持未知状态。限制重试次数,不要为了绕开不确定性另造 ID。
- 仅在字节必须跨组件时使用 URI 合同. 文件交接应由适当 Provider 提供 content URI,并通过文档化 Intent 机制只授予必要的临时权限;默认只读,只有明确必要的编辑流程才允许写入。URI 字符串本身只是定位符,不是授权;Provider 策略和实际 grant 都必须允许该接收方打开资源。测试授权过期和撤销,并关闭每个打开的描述符。结果 ID 是查找元数据,仅有文件系统路径既不是跨应用合同,也不是权限授予。
- 分别测试恢复、保留和清理. 在持久化前、写入后但导航前、交易边界、接收方读取 ID 后以及重试期间注入故障。确认不同结果修订不会互相覆盖;过期记录按策略清除;URI 授权按预期结束;描述符关闭;重复副作用由操作所有者拒绝,而不是依赖本地 UI 状态去假设不会发生。
让每个阶段的状态都可观察。失败信息应指出阶段、模型、运行时和恢复动作,同时避免记录用户私密内容。
验收标准
- SavedState 与 Intent 只包含有界导航元数据;生成结果字节留在声明的结果所有者中,直到发生经过验证的清理事件。
- 合成 Parcel 大小只作为夹具证据报告,不作为单次 Binder 上限,也不证明并发事务不会触发失败。
- 异常后,操作在所有者查询同一 ID 前保持可恢复的未知状态;重试须有终态未提交确认或所有者端原子/串行幂等,重复副作用会被拒绝。
- 文件交接使用经过测试的 content URI、Provider 权限和实际最小授权,默认只读并说明有效期;URI 字符串本身不构成授权。
决策对照表
| 维度 | 选择或证据 | 解读方式 |
|---|---|---|
| Intent 或 saved state 携带完整结果 | 每次界面切换都序列化全部文本或对象图 | 小型临时值实现简单,但结果复杂度和共享交易负载会增加序列化成本;不应作为大型生成输出的默认方案。 |
| 持久化结果加稳定 ID | 保存普通数据,只传短操作/结果引用 | 能让导航载荷保持有界,并支持异常后由所有者查询状态;仍需明确授权、版本、过期和清理检查。 |
| 文件字节使用 content URI | 通过 Provider 暴露资源并在 Intent 中授予 URI 权限 | 适用于另一组件确实需要访问文件的情况;URI 字符串本身不授予访问,Provider 许可和实际范围授权都必须存在。默认只读并测试期限。 |
| 把数据拆成多次 Binder 调用 | 通过多个交易分块发送大载荷 | 有意设计的流式协议可能使用该办法,但会增加顺序、部分写入、重试和清理状态;结果要跨生命周期保留时,它不能取代持久所有权。 |
需要避免的失败模式
- 把 Binder 共享的 1 MB 缓冲误说成每个 Intent 都可用的有效上限。
- 凭 TransactionTooLargeException 判断请求未执行,立即创建新任务或重复副作用。
- 把结果 ID 当授权,或把 content URI grant 当永久可用。
- 将 Binder 传输问题混同于 JSON 校验、进程恢复设计或文件描述符泄漏。
还要避免静默回退、版本未固定、缺少取消处理,以及把不同配置的结果混在一起下结论。失败运行也应与成功记录一并保存。
最小复现记录
| 层级 | 记录内容 |
|---|---|
| 设备 | 厂商、型号、芯片、内存档位、操作系统版本 |
| 软件 | 应用版本和 Git 提交号 |
| 模型 | 系列、变体、版本、格式、文件长度、摘要、量化方式 |
| 运行时 | 名称、版本、请求后端及实际后端证据 |
| 工作负载 | 样例版本、输入摘要、提示词摘要、输出策略 |
| 结果 | 完成、失败、取消、回退及保护隐私的诊断信息 |
发布检查表
- ☐ 主要搜索问题已回答,且没有未经支持的数字。
- ☐ 所有模型文件和运行时版本均已固定。
- ☐ 代表性任务和失败处理策略均有说明。
- ☐ 生命周期、取消、清理和回退均已测试。
- ☐ 用户内容与网络边界均有说明。
- ☐ 结论只适用于被记录的配置。
- ☐ 新增测试结果时链接到原始方法或证据。
来源与相关证据
- Android Developers — TransactionTooLargeException
- Android Developers — Parcel.dataSize()
- Android Developers — Parcelables 和 Bundle
- Android Developers — 保存 UI 状态
- Android Developers — 安全文件共享
中文部署与排错专题见。奇连 AI 端侧专题。
常见问题
1 MB 是每个 Android Intent 的最大载荷吗?
不是。Android 描述的是由同一进程正在进行的 Binder 事务共享的 1 MB 缓冲,不是可靠的单 Intent 可用额度。并发事务和序列化开销都会影响结果,因此应保持载荷很小并验证实际交接路径。
TransactionTooLargeException 能告诉我推理是否已经运行吗?
不能。Android 文档指出,请求可能没到服务端,也可能是响应未能返回;仅凭异常无法区分。重试前应使用原操作 ID 查询同一个任务所有者。
Parcel.dataSize() 能证明交接一定成功吗?
不能。它报告该 Parcel 夹具所含的字节,不包括其他并发 Binder 事务,也不认证系统交易阈值。只能把它作为比较诊断证据,而非兼容性保证。
传递结果 ID 就足以让另一个组件读取吗?
不够。ID 与 content URI 字符串都只是定位符;结果所有者须鉴权 ID,文件访问还需要允许访问的 Provider 和实际范围 grant。默认只读,并检查授权何时过期。
导航交易失败后应该立即重试吗?
不要盲目重试。响应侧失败可能发生在所有者已处理请求之后,查不到记录也可能是任务仍在运行。只有所有者确认旧尝试已终止且未提交,或相同 ID 经所有者原子/串行去重边界时才重试;否则保持未知状态。