欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TransactionTooLargeException异常

程序员文章站 2022-03-02 13:47:42
...

 

一、问题以及解决方案

TransactionTooLargeException异常是一个很不常见的异常,开发几年了,首次遇到这个异常,一部分手机会出现这种情况,当时还很惊奇。最后经查找原来是Activity启动时候intent数据传递过大发生的。当时是一个分享功能的偶发bug,在分享时候传递数据包括标题、链接,网址,截图等参数,截图传递的是截取的Bitmap,果然是Bitmap太大了,导致部分机型TransactionTooLargeException:

    System.err: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 2056292 bytes
                at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3998)

经过代码追踪,发现intent在putBundle之前把Bitmap添加到Bundle里面,这才是根源,最后把Bitmap经过质量压缩为原来的百分之30才不崩溃了:

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    resource.compress(Bitmap.CompressFormat.JPEG, 30, bos);
    byte[] bytes = bos.toByteArray();
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

二、异常原因

从上面的问题上可以看出通过intent在页面间传递数据是有大小限制的,但通常我们平时传递少量数据的时候是没问题的。在Activity之前传递数据的时候从intent中携带的数据是需要从APP进程传输到AMS进程,再由AMS进程传输到目标Activity所在进程。但是目标的Activity不一定是APP所在的进行,有可能是其他进程。因为Activity的startActivity方法是原生支持跨进程通信的,例如我们通过隐式意图启动其他APP的Activity或者目标Activity在Manifest.xml配置了process属性,这时候当前Activity和目标Activity就不再同一个进程。这也不难理解startActivity传递数据的数据层不是在APP层面处理的,而是在binder中进行数据传递。普通的由Zygote孵化而来的用户进程,所映射的Binder内存大小是不到1M的,如果传输说句超过这个大小,系统就会报错,因为Binder本身就是为了进程间频繁而灵活的通信所设计的,并不是为了拷贝大数据而使用的,TransactionTooLargeException源码注释也可以看出:

 * The Binder transaction buffer has a limited fixed size, currently 1Mb, which
 * is shared by all transactions in progress for the process.  Consequently this
 * exception can be thrown when there are many transactions in progress even when
 * most of the individual transactions are of moderate size.