解决android.os.TransactionTooLargeException

做安卓开发的时候,有的时候会遇见如下的crash log:

    07-05 13:34:55.577 6523-6523/com.fooww.soft.android.Presentation W/System.err: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 2056292 bytes
        at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3998)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:159)

这个bug光看log,大概能猜到原因,但其实很难定位到具体是哪里的问题,尤其是一个Activity包含许多个Fragment。
先说说出现的原因,当你在Activity中的Fragment中,你在使用onSaveInstanceState()方法的时候,存入了过大的数据,导致Activity在数据恢复的时候,抛出异常。

任何时候在你的一个Activity中遇见 TransactionTooLargeException崩溃异常,都意味着这个Activity为了数据恢复而保存的数据,但是一个或多个Bundle发送的数据过大。一次事务所发送的数据是有大小限制的,约1MB。

但是有的时候因为业务逻辑复杂的时候,保存的数据有许多,到底是哪些数据超过了限制呢?为了定位这个问题,我们可以使用下面这个工具来进行定位:

Toolargetool

在你的Activity中进行操作,就会在 logcat 中出现日志,例如

07-05 13:34:47.898 6523-6523/com.fooww.soft.android.Presentation D/TooLargeTool: Fragment.onSaveInstanceState wrote: Bundle@227937474 contains 4 keys and measures 761.0 KB when serialized as a Parcel
    * CLICKPOSITION = 0.0 KB
    * android:view_state = 0.7 KB
    * android:user_visible_hint = 0.1 KB
    * LSTIHITEMS = 760.2 KB
    * fragment arguments = Bundle@211783351 contains 3 keys and measures 1.2 KB when serialized as a Parcel
    * HouseType = 0.2 KB
    * HasHandled = 0.0 KB
    * ConditionSecond = 0.9 KB
07-05 13:34:52.908 6523-6523/com.fooww.soft.android.Presentation D/TooLargeTool: Fragment.onSaveInstanceState wrote: Bundle@13810387 contains 3 keys and measures 1,289.8 KB when serialized as a Parcel
    * CLICKPOSITION = 0.0 KB
    * android:view_state = 0.7 KB
    * LSTIHITEMS = 1,289.1 KB
    * fragment arguments = Bundle@183874957 contains 3 keys and measures 1.2 KB when serialized as a Parcel
    * HouseType = 0.2 KB
    * ConditionRent = 0.9 KB
    * HasHandled = 0.0 KB

这个工具简直是神器有没有,可以看到所有保存到Bundle中的数据及其占用内存大小,很容易的我们发现LSTIHITEMS这个对象包含了 1,289.1 KB的数据,超过了1MB导致后来的TransactionTooLargeException

知道了问题出现的原因,那我们就要接着说说解决办法。其实所有的办法总结起来就是不把过大的数据放进Bundle。除了Bundle,存哪都行。

1.如果Activity中使用了FragmentStatePagerAdapter,换成FragmentPagerAdapter,或者复写saveState()。原因是因为
FragmentStatePagerAdaptersaveState()方法,会对每一个生成的Fragment都保存其Bundle数据,一旦Fragment创建次数过大,比如说...创建了100次,即使Fragment被销毁了,Bundle数据还是被保存下来了, 那么所有的Bundle数据合起来也是很大的。

@Override
public Parcelable saveState() {
    Bundle state = null;
    if (mSavedState.size() > 0) {
        state = new Bundle();
        Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
        mSavedState.toArray(fss);
        state.putParcelableArray("states", fss);
    }
    for (int i=0; i<mFragments.size(); i++) {
        Fragment f = mFragments.get(i);
        if (f != null && f.isAdded()) {
            if (state == null) {
                state = new Bundle();
            }
            String key = "f" + i;
            mFragmentManager.putFragment(state, key, f);
        }
    }
    return state;
} 

2.将要保存的数据存成静态变量。
3.持久化。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,892评论 25 709
  • 《Android Fragment完全解析,关于碎片你所需知道的一切》 我们都知道,Android上的界面展示都是...
    cxm11阅读 6,657评论 2 19
  • 偶然拿一张人像做了微信头像,同事有几个都以为是我小时候。 那么,就画一下小时候的我吧。 但愿我的小时候,像你这么可...
    晶童阅读 1,248评论 0 1
  • 使用RVM(Ruby Version Manager) 切换之后,整个ruby环境切换,随之gem的环境也切换了所...
    Derek重名了阅读 4,666评论 0 0
  • 今天开车走在高速上,思绪却回到了当初在驾校学习考驾照的2008年。 当时是在暑假,奥运会正如火如荼的开展着,我跟朋...
    乌卓阅读 1,573评论 0 2