• 解决线上概率性异常 TransactionTooLargeException


    一、问题描述

    在这里插入图片描述

    根据经验,看到这个问题描述,第一时间想到的是 Intent 传递了太大的数据,但是进行堆栈分析后,发现并不是我想的这样

    二、堆栈分析

    查看出错的堆栈

    在这里插入图片描述

    可以看到崩溃是出现在某个 Activity stop 的时候,跟 intent 传递数据是不符合的,查看出错的页面

    在这里插入图片描述

    是在 PictureSelectActivity onPaused 后崩溃的,也确实和 intent 传递数据没什么关系

    从堆栈中我们可以看到调用了 BinderProxy.transact 方法,然后调用到了 native 层,我们顺腾摸瓜,最后找到了报错代码

    在这里插入图片描述

    在这里插入图片描述

    parcelSize 只要大于 200KB,就会报错,而 parcelSize 则对应于 BinderProxy.transact 方法的 Parcel data 对象,那么问题就指向了为何 data 会超过 200KB

    但是现在有个疑问是,到底要怎样才能复现崩溃呢?因为我们现在知道了报错代码,但是并不知道什么场景会报错。

    三、尝试复现问题

    通过对页面数据的排查,发现出错的页面都是 PictureSelectActivity,且都是在该 Activity onPause 之后出错的,那么查询代码,看 PictureSelectActivity onPause 之后做了什么呢?

    可能1:

    在这里插入图片描述

    上面是选完图片后,通过 setResult 把数据传递回上一个 Activity,只是传了一个 urlList,数据量并不大,所以排除这个可能

    可能2:

    PictureSelectActivity 中有几个 Fragment,Activity 与 Fragment 之间传递数据使用了 Bundle,但是查看代码后发现传递的数据量很小,且不符合

    ActivityStop 的时机,排除

    可能3:

    通过查阅资料

    https://www.cnblogs.com/tgltt/p/9834584.html

    找到另外一种可能

    问题原因:FragmentStatePagerAdapter 的 saveState() 实现有缺陷,因为其默认实现会持续保存历史Fragment实例的状态数据历史,在逐渐地积累、保存数据后,最终导致发送的数据包体积超过限制200KB 。

    在这里插入图片描述

    saveState 被 ViewPager 的 onSaveInstanceState 调用了

    在这里插入图片描述

    当activity有可能被系统回收的情况下,系统将调用 Activity 的 onSaveInstanceState(Bundle outState) 进行数据的保存,以便 activity 重新创建的时候,可以恢复数据,而 Activity 的 onSaveInstanceState(Bundle outState)

    被调用后会调用 View 的 onSaveInstanceState

    onSaveInstanceState(Bundle outState)会在以下情况被调用:
    1、当用户按下HOME键时。
    2、从最近应用中选择运行其他的程序时。
    3、按下电源按键(关闭屏幕显示)时。
    4、从当前activity启动一个新的activity时。
    5、屏幕方向切换时(无论竖屏切横屏还是横屏切竖屏都会调用)。

    在前4种情况下,当前activity的生命周期为:

    onPause -> onSaveInstanceState -> onStop

    为了印证这种可能,我们让 PictureSelectActvity 的图片浏览器浏览了 500 张图片,然后按下 HOME 键,这时候果然出现了崩溃,也就印证了崩溃的原因了

    总结:问题的原因是 当 Activity 被隐藏时,其 onSaveInstanceState(Bundle outState) 被调用进行数据的保存,最终调用了 FragmentStatePagerAdapter 的 saveState(),而 saveState() 实现有缺陷,因为其默认实现会持续保存历史Fragment实例的状态数据历史,在逐渐地积累、保存数据后,最终导致发送的数据包体积超过限制200KB 。

    四、解决问题

    重写 FragmentStatePagerAdapter 的 saveState() ,saveState() 的时候不保存任何的数据

    加粗样式

    影响范围:因为保存的数据只有在 Activity 被回收,然后恢复 Activity 的时候有用,而这种情况下不恢复之前的状态其实影响不大,所以这种方案是可行的

    为了避免其他业务也出现类似的情况,所以封装出一个基类,只有那些 ViewPager 的页数比较多的场景才需要继承这个类

    在这里插入图片描述

  • 相关阅读:
    YOLOV:图像对象检测器在视频对象检测方面表现也很不错
    pytorch中的hook机制register_forward_hook
    使用mysql语句进行外连接
    跨域的解决方案
    LeetCode 45. 跳跃游戏 II
    【多媒体信号处理课程】Course Introduction-1 AVI Walk Through-2 Audio coding basics-3 AI翻译
    【视觉算法系列3】在自定义数据集上训练 YOLO NAS(下篇)
    Web3项目灵魂所在之智能合约编写(Web3项目一实战之二)
    2022“杭电杯”中国大学生算法设计超级联赛(4) Link with Bracket Sequence II
    java+maven+testng+allure+git搭建持续集成报告配置
  • 原文地址:https://blog.csdn.net/linhaosheng123456/article/details/126529607