为了账号安全,请及时绑定邮箱和手机立即绑定

如何处理TransactionTooLargeException

如何处理TransactionTooLargeException

茅侃侃 2019-06-27 17:07:29
如何处理TransactionTooLargeException我有一个TransactionTooLargeException..不能重复。在文档里写着Binder事务失败,因为它太大了。在远程过程调用期间,参数和调用的返回值作为存储在Binder事务缓冲区中的Packcel对象传输。如果参数或返回值太大,无法适应事务缓冲区,那么调用将失败,TransactionTooLargeException将被抛出。...当远程过程调用抛出TransactionTooLargeException时,有两种可能的结果。客户端无法将其请求发送到服务(最可能的情况是参数太大,无法适应事务缓冲区),或者服务无法将其响应发送回客户端(最可能的情况是返回值太大,无法适应事务缓冲区)。...所以在某个地方,我正在传递或接收一些超越未知极限的论点。哪里?堆栈跟踪没有显示任何有用的内容:java.lang.RuntimeException: Adding window failedat android.view.ViewRootImpl.setView(ViewRootImpl.java:548)at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)at android.view.Window$LocalWindowManager.addView(Window.java:557)at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)at android.app.ActivityThread.access$600(ActivityThread.java:139)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:154)at android.app.ActivityThread.main(ActivityThread.java:4977)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)at dalvik.system.NativeStart.main(Native Method)Caused by: android.os.TransactionTooLargeExceptionat android.os.BinderProxy.transact(Native Method)at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)它似乎与观点有关?这与远程过程调用有什么关系?可能很重要:Android版本:4.0.3,设备:HTC One X
查看完整描述

3 回答

?
UYOU

TA贡献1878条经验 获得超4个赞

我遇到了这个问题,我发现当服务和应用程序之间交换了大量数据时(这涉及到传输大量缩略图)。实际上,数据大小约为500 kb,IPC事务缓冲区大小设置为1024 KB。我不知道为什么它超过了事务缓冲区。

当您通过意图附加传递大量数据时,也会发生这种情况。

当您在应用程序中获得此异常时,请分析您的代码。

  1. 您是否在服务和应用程序之间交换大量数据?
  2. 使用意图共享大量数据(例如,用户从图片库共享中选择大量文件,所选文件的URI将使用intents传输)
  3. 从服务接收位图文件
  4. 等待Android用大量数据进行响应(例如,当用户安装大量应用程序时,getInstalledApplications()
  5. 将applyBatch()与许多未完成的操作一起使用

当您得到此异常时,如何处理?

如果可能的话,将大操作分割成小块,例如,不要用1000个操作调用applyBatch(),而要调用每个操作100个。

不要在服务和应用程序之间交换大量数据(>1MB)。

我不知道怎么做,但是不要查询Android,它可以返回巨大的数据:-)


查看完整回答
反对 回复 2019-06-27
?
慕码人2483693

TA贡献1860条经验 获得超9个赞

这并不是一个明确的答案,但它可能会揭示一些原因。TransactionTooLargeException帮助找出问题所在。

尽管大多数答案都涉及到传输的大量数据,但我看到这个异常是在大量滚动和缩放并反复打开ActionBar旋转菜单之后抛出的。碰撞发生在敲击动作杆上。(这是一个自定义映射应用程序)

唯一传递的数据似乎是从“输入分配器”到应用程序的接触。我认为这不能合理地相当于“事务缓冲区”中接近1MB的任何东西。

我的应用程序运行在一个1.6GHz的四核设备上,使用3个线程进行重举,为UI线程保留一个内核。此外,该应用程序使用Android:LargeHeap,还剩下10 MB未使用的堆,还有100 MB的空间用于堆的增长。所以我不会说这是资源问题。

坠机前总是有以下几行:

W/InputDispatcher( 2271): channel ~ Consumer closed input channel or an error occurred.  events=0x9E/InputDispatcher( 2271): channel ~ Channel is unrecoverably broken and will be disposed!E/JavaBinder(28182): !!! FAILED BINDER TRANSACTION !!!

它们不是按这个顺序印刷的,但(据我所查)发生在同一毫秒内。

为了清晰起见,堆栈跟踪本身与问题相同:

E/AndroidRuntime(28182): java.lang.RuntimeException: Adding window failed..E/AndroidRuntime(28182): Caused by: android.os.TransactionTooLargeException

深入研究AndroidOne的源代码,可以发现以下几行:

frameworks/base/core/jni/android_util_Binder.cpp:

case FAILED_TRANSACTION:
    ALOGE("!!! FAILED BINDER TRANSACTION !!!");
    // TransactionTooLargeException is a checked exception, only throw from certain methods.
    // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
    //        but it is not the only one.  The Binder driver can return BR_FAILED_REPLY
    //        for other reasons also, such as if the transaction is malformed or
    //        refers to an FD that has been closed.  We should change the driver
    //        to enable us to distinguish these cases in the future.
    jniThrowException(env, canThrowRemoteException            ? "android/os/TransactionTooLargeException"
                    : "java/lang/RuntimeException", NULL);

在我看来,这听起来像是我碰到了这个没有文档的特性,在这里,事务失败了,而不是因为一个交易是TooLarge。他们应该给它起个名字TransactionTooLargeOrAnotherReasonException.

此时我没有解决这个问题,但是如果我找到有用的东西,我会更新这个答案。

最新情况:结果,我的代码泄露了一些文件描述符,在Linux(通常是1024)中,文件描述符的数量最大,这似乎触发了异常。所以这毕竟是一个资源问题。我通过打开/dev/zero1024次,导致UI相关操作出现各种奇怪的异常,包括上述异常,甚至一些SIGSEGV。显然,在整个Android系统中,未能打开文件/套接字并不是非常干净的处理/报告。


查看完整回答
反对 回复 2019-06-27
?
白衣非少年

TA贡献1155条经验 获得超0个赞

这个TransactionTooLargeException已经困扰我们四个月了,我们终于解决了这个问题!

发生的事情是我们用的是FragmentStatePagerAdapter在.ViewPager..用户将分页浏览并创建100+片段(它是一个读取应用程序)。

虽然我们在destroyItem(),在仙女座FragmentStatePagerAdapter有一个bug,它保存了对以下列表的引用:

private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();

当安卓系统FragmentStatePagerAdapter尝试保存状态,它将调用该函数。

@Overridepublic 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;}

如您所见,即使您正确地管理FragmentStatePagerAdapter类,则基类仍将存储Fragment.SavedState为每一个曾经创造的片段。这个TransactionTooLargeException当该数组转储到parcelableArray而且操作系统也不喜欢它的100多个项目。

因此,我们的修复方法是覆盖saveState()方法和储存任何东西"states".

@Overridepublic Parcelable saveState() {
    Bundle bundle = (Bundle) super.saveState();
    bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
    return bundle;}


查看完整回答
反对 回复 2019-06-27
  • 3 回答
  • 0 关注
  • 1474 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信