美文网首页Android开发Android
解决android.os.TransactionTooLarge

解决android.os.TransactionTooLarge

作者: 一方乌鸦 | 来源:发表于2018-07-09 12:44 被阅读55次

    做安卓开发的时候,有的时候会遇见如下的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.持久化...持久化的时候可以使用这个工具:

    Bridge

    4.将targetSdkVersion 降到 23及以下,此时数据超了1MB,据说只会有warning,不会crash,这个我没试过...大家酌情考虑。

    相关文章

      网友评论

        本文标题:解决android.os.TransactionTooLarge

        本文链接:https://www.haomeiwen.com/subject/hfqzuftx.html