首页 文章

如何处理TransactionTooLargeException

提问于
浏览
185

我得到了一个应用程序TransactionTooLargeException的错误跟踪 . 不可重复,从未有过 . 在文档中说

Binder交易失败,因为它太大了 . 在远程过程调用期间,调用的参数和返回值将作为存储在Binder事务缓冲区中的Parcel对象进行传输 . 如果参数或返回值太大而不适合事务缓冲区,则调用将失败并抛出TransactionTooLargeException . ...当远程过程调用抛出TransactionTooLargeException时,有两种可能的结果 . 客户端无法将其请求发送到服务(很可能,如果参数太大而无法容纳在事务缓冲区中),或者服务无法将其响应发送回客户端(最有可能的话,如果返回值为太大而不适合事务缓冲区) . ...

所以,好吧,我正在传递或接收超出某个未知限制的参数 . 但是哪里?

堆栈跟踪不会显示我的文件中的任何内容:

java.lang.RuntimeException: Adding window failed
at 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.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
... 16 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
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)

它似乎与视图有关,因为所有的Window / View行?这与远程过程调用有什么关系?我该如何查找此错误的原因?

在应用程序中我只使用Webservices,我没有使用Service类,Web服务是“远程过程调用”还是其他可能......?

附:也许它很重要:Android版本:4.0.3,设备:HTC One X.

30 回答

  • 0

    对我来说 TransactionTooLargeException 当我试图通过意图将 large bitmap 图像从一个活动发送到另一个活动时发生了 . 我使用Application's Global Variables解决了这个问题 .

    例如,如果要将大型位图图像从活动 A 发送到活动 B ,则将该位图图像存储在全局变量中

    ((Global) this.getApplication()).setBitmap(bitmap);
    

    然后启动活动B并从全局变量读取

    Bitmap bitmap = ((Global) this.getApplication()).getBitmap();
    
  • 2

    有这么多地方可以发生 TransactionTooLargeException --这是Android 8的新功能 - 如果内容太大,有人只是开始输入EditText时会崩溃 .

    它与AutoFillManager(API 26中的新增内容)和 StartSessionLocked() 中的following代码相关:

    mSessionId = mService.startSession(mContext.getActivityToken(),
                mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                mCallback != null, flags, mContext.getOpPackageName());
    

    如果我理解正确,这会调用自动填充服务 - 在 Binders 中传递AutofillManagerClient . 当EditText有很多内容时,它似乎会导致TTLE .

    一些事情可能会缓解它(或者无论如何我都在测试):在EditText的xml布局声明中添加 android:importantForAutofill="noExcludeDescendants" . 或者在代码中:

    EditText et = myView.findViewById(R.id.scriptEditTextView);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        et.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
    }
    

    第二个可怕的,可怕的解决方法也可能是覆盖 performClick()onWindowFocusChanged() 方法来捕获TextEdit子类本身的错误 . 但我真的很明智......

  • 19

    作为Intent,内容提供商,Messenger,所有系统服务,如电话,振动器等,都使用Binder的IPC基础设施提供商 . 此外,活动生命周期回调也使用此基础设施 .

    1MB是特定时刻系统中执行的所有 Binders 事务的总限制 .

    如果发送意图时发生了大量事务,即使额外数据不大,也可能会失败 . http://codetheory.in/an-overview-of-android-binder-framework/

  • 129

    在我的情况下,在本机库与SIGSEGV崩溃后,我将TransactionTooLargeException作为二次崩溃 . 未报告本机库崩溃,因此我只收到TransactionTooLargeException .

  • 3

    当我尝试通过Intent发送位图时,我遇到了同样的问题,同时当它发生时,我折叠了应用程序 .

    它是如何在本文中描述的enter link description here它发生在一个Activity正在停止的过程中,这意味着Activity正在尝试将其保存的状态Bundle发送到系统操作系统,以便以后安全保存(在配置更改或进程死亡之后) )但它发送的一个或多个Bundle太大了 .

    我通过在我的Activity中重写onSaveInstanceState来解决它:

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // super.onSaveInstanceState(outState);
    }
    

    并评论称超级 . 这是一个肮脏的黑客,但它工作得很好 . Bitmap成功发送而没有崩溃 . 希望这会对某人有所帮助 .

  • 1

    在尝试批量插入大型ContentValues []时,我在syncadapter中得到了这个 . 我决定修复如下:

    try {
        count = provider.bulkInsert(uri, contentValueses);
    } catch (TransactionTooLarge e) {
        int half = contentValueses.length/2;
        count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, 0, half));
        count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, half, contentValueses.length));
    }
    
  • 9

    writeToParcel(Parcel dest,int flags)方法中的这一行代码帮助我摆脱了TransactionTooLargeException .

    dest=Parcel.obtain();
    

    在此代码之后,我只将所有数据写入parcel对象,即dest.writeInt()等 .

  • 16

    最近我在使用Android的 Contacts Provider 时遇到了一个有趣的案例 .

    我需要从内部联系人数据库加载联系人的照片,并根据系统架构,所有这些数据都通过查询提供给Contacts Provider .

    由于它作为一个单独的应用程序工作 - 所有类型的数据传输都是使用Binder机制执行的,因此Binder缓冲区在这里发挥作用 .

    我的主要错误是 I didn't close 带有blob数据的 Cursor 来自Contacts Provider,因此分配给了提供程序增加,这膨胀了Binder缓冲区,直到我在LogCat输出中收到大量的 !!!FAILED BINDER TRANSACTION!!! 消息 .

    因此,主要的想法是,当您使用外部内容提供商并从中获取 Cursor 时,请在完成使用它们时始终关闭它 .

  • 0

    一个解决方案是让app将ArrayList(或导致问题的任何对象)写入文件系统,然后通过Intent将对该文件的引用(例如,filename / path)传递给IntentService,然后让IntentService检索文件内容并将其转换回ArrayList .

    当IntentService完成该文件时,它应该删除它或通过本地广播将指令传递回应用程序以删除它创建的文件(传回提供给它的相同文件引用) .

    有关详细信息,请参阅my answer to this related problem .

  • 0

    可以使用:

    android:largeHeap="true"
    

    在应用程序标记下的Android Manifest中 .

    这解决了我的问题!

  • 0

    对于那些在寻找TransactionTooLargeException为何出现的答案时感到非常失望的人, try to check what you save in instance state.

    在编译/ targetSdkVersion <= 23 we have only internal warning 关于大型保存状态,但没有任何崩溃:

    E/ActivityThread: App sent too much data in instance state, so it was ignored
        android.os.TransactionTooLargeException: data parcel size 713856 bytes
        at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(Binder.java:615)
        at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
        at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6044)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
    

    但在这种情况下编译/ targetSdkVersion >= 24 we have real RuntimeException crash

    java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 713860 bytes
        at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3737)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6044)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
     Caused by: android.os.TransactionTooLargeException: data parcel size 713860 bytes
       at android.os.BinderProxy.transactNative(Native Method)
       at android.os.BinderProxy.transact(Binder.java:615)
       at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
       at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
       at android.os.Handler.handleCallback(Handler.java:751) 
       at android.os.Handler.dispatchMessage(Handler.java:95) 
       at android.os.Looper.loop(Looper.java:154) 
       at android.app.ActivityThread.main(ActivityThread.java:6044) 
       at java.lang.reflect.Method.invoke(Native Method) 
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
    

    What to do?

    将数据保存在本地数据库中,并仅将id保存在实例状态,您可以使用它来检索此数据 .

  • 28

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

    发生的事情是我们在 ViewPager 中使用 FragmentStatePagerAdapter . 用户将翻页并创建100个片段(它是一个阅读应用程序) .

    虽然我们在 destroyItem() 中正确管理了片段,但是在 FragmentStatePagerAdapter 的Androids实现中存在一个错误,它保留了对以下列表的引用:

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

    当Android的 FragmentStatePagerAdapter 尝试保存状态时,它会调用该函数

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

    如您所见,即使您正确管理 FragmentStatePagerAdapter 子类中的片段,基类仍将为创建的每个片段存储 Fragment.SavedState . 当该数组被转储到 parcelableArray 并且操作系统不喜欢100个项目时,会发生 TransactionTooLargeException .

    因此,我们的修复是覆盖 saveState() 方法并 not 存储 "states" 的任何内容 .

    @Override
    public 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;
    }
    
  • 8

    这个问题没有一个具体原因 . 对我来说,在我的Fragment类中,我这样做:

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        View rootView = inflater.inflate(R.layout.snacks_layout, container); //<-- notice the absence of the false argument
        return rootView;
    }
    

    而不是这个:

    View rootView = inflater.inflate(R.layout.softs_layout, container, false);
    
  • 1

    在将(发送广播)位图对象传输到广播接收器时,我遇到了同样的问题 .

    intent.putExtra("image", bitmapImage);
    

    所以不要将它们作为位图发送 . 我将位图转换为字节数组 . 令我惊讶的是它有效!!!我想知道为什么Android不允许使用Bitmap传输大量数据但允许相同的通过字节数组 .

    intent.putExtra("imageInByteArray", convertBitmapToByteArray(bitmapImage));
    

    在接收器上我将字节数组转换回位图,这解决了我的问题 .

  • 0

    我也面临着这个问题,因为Bitmap数据从一个活动传递到另一个活动,但我通过将我的数据作为静态数据来解决这个问题,这对我来说非常有用

    在活动中:

    public static Bitmap bitmap_image;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
       bitmap_image=mybitmap;
    }
    

    在第二项活动中:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
       Bitmap mybitmap=first.bitmap_image;
    }
    
  • 37

    将应用程序发送到后台时通常会抛出此异常 .

    所以我决定使用数据片段方法来完全规避 onSavedInstanceStae 生命周期 . 我的解决方案还处理复杂的实例状态并尽快释放内存 .

    首先,我创建了一个简单的Fargment来存储数据:

    package info.peakapps.peaksdk.logic;
    import android.app.Fragment;
    import android.app.FragmentManager;
    import android.os.Bundle;
    
    /**
     * A neat trick to avoid TransactionTooLargeException while saving our instance state
     */
    
    public class SavedInstanceFragment extends Fragment {
    
        private static final String TAG = "SavedInstanceFragment";
        private Bundle mInstanceBundle = null;
    
        public SavedInstanceFragment() { // This will only be called once be cause of setRetainInstance()
            super();
            setRetainInstance( true );
        }
    
        public SavedInstanceFragment pushData( Bundle instanceState )
        {
            if ( this.mInstanceBundle == null ) {
                this.mInstanceBundle = instanceState;
            }
            else
            {
                this.mInstanceBundle.putAll( instanceState );
            }
            return this;
        }
    
        public Bundle popData()
        {
            Bundle out = this.mInstanceBundle;
            this.mInstanceBundle = null;
            return out;
        }
    
        public static final SavedInstanceFragment getInstance(FragmentManager fragmentManager )
        {
            SavedInstanceFragment out = (SavedInstanceFragment) fragmentManager.findFragmentByTag( TAG );
    
            if ( out == null )
            {
                out = new SavedInstanceFragment();
                fragmentManager.beginTransaction().add( out, TAG ).commit();
            }
            return out;
        }
    }
    

    然后在我的主要Activity上完全绕过保存的实例循环,并将respoinsibilty推迟到我的数据Fragment . 无需在Fragments本身上使用它,sice将其状态自动添加到Activity的状态中:

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    
        SavedInstanceFragment.getInstance( getFragmentManager() ).pushData( (Bundle) outState.clone() );
        outState.clear(); // We don't want a TransactionTooLargeException, so we handle things via the SavedInstanceFragment
    }
    

    剩下的就是弹出保存的实例:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(SavedInstanceFragment.getInstance(getFragmentManager()).popData());
    }
    
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState( SavedInstanceFragment.getInstance( getFragmentManager() ).popData() );
    }
    

    详细信息:http://www.devsbedevin.com/avoiding-transactiontoolargeexception-on-android-nougat-and-up/

  • 1

    我找到了这个的根本原因(我们得到了“添加窗口失败”和文件描述符泄漏,如mvds所说) .

    Android 4.4的 BitmapFactory.decodeFileDescriptor() 中有一个bug . 仅当 inPurgeableinPurgeableinInputShareable 设置为 true 时才会发生 . 这导致许多地方的许多问题与文件交互 .

    请注意,该方法也是从 MediaStore.Images.Thumbnails.getThumbnail() 调用的 .

    Universal Image Loader受此问题的影响 . 毕加索和格莱德似乎没有受到影响 . https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020

  • 2

    所以对我们来说,我们试图通过AIDL接口将太大的对象发送到远程服务 . 交易规模不能超过1MB . 请求被分解为512KB的单独块,并通过接口一次发送一个 . 我知道一个残酷的解决方案,但嘿 - 它的Android :(

  • 8

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

    当您通过intent extras传递大量数据时,也会发生这种情况

    当你在您的应用程序中获取此异常,请分析您的代码 .

    • 您是否在服务和应用程序之间交换大量数据?

    • 使用意图共享大量数据(例如,用户从图库共享新闻共享中选择大量文件,所选文件的URI将使用意图传输)

    • 从服务接收位图文件

    • 等待android用巨大的数据回复(例如,当用户安装了很多应用程序时,getInstalledApplications())

    • 使用applyBatch(),其中有许多操作待定

    How to handle when you get this exception

    如果可能,将大操作拆分为小块,例如,而不是使用1000次操作调用applyBatch(),每次调用100 .

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

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

  • 1

    重要的是要了解事务缓冲区限制为1 MB,无论设备功能或应用程序如何 . 此缓冲区用于您进行的每个API调用,并在应用程序当前正在运行的所有事务中共享 .

    我相信它也有一些特定的对象,比如parcels和 (Parcel.obtain()) ,所以始终将每个 obtain()recycle() 匹配很重要 .

    即使返回的数据小于1 MB(如果其他事务仍在运行),返回大量数据的API调用也很容易发生此错误 .

    例如, PackageManager.getInstalledApplication() 调用返回已安装的所有应用的列表 . 添加特定标志允许检索大量额外数据 . 这样做可能会失败,因此建议不要检索任何额外的数据并按应用程序检索这些数据 .

    但是,呼叫可能仍然失败,因此用 catch 围绕它是很重要的,并且必要时可以重试 .

    据我所知,除了重试并确保尽可能少地检索信息之外,没有解决此类问题的方法 .

  • 3

    我也在三星S3上遇到了这个例外 . 我怀疑有两个根本原因,

    • 你有加载和占用太多内存的位图,使用缩小尺寸

    • 你在drawable-_dpi文件夹中缺少一些drawables,android在drawable中查找它们,并调整它们的大小,使你的setContentView突然跳转并使用大量内存 .

    使用DDMS并在播放应用程序时查看堆,这将为您提供有关setcontentview创建问题的一些指示 .

    我复制了所有文件夹中的所有drawables以摆脱问题2 .

    问题已解决 .

  • 9

    当我在我的应用程序中处理 WebView 时,它会发生 . 我认为这与 addView 和UI资源有关 . 在我的应用程序中,我在_412506中添加了一些代码,如下所示,然后运行正常:

    @Override
    protected void onDestroy() {
        if (mWebView != null) {
            ((ViewGroup) mWebView.getParent()).removeView(mWebView);  
            mWebView.removeAllViews();  
            mWebView.destroy();
        }
        super.onDestroy();
    }
    
  • 0

    确保不要放入大尺寸的Intent对象数据 . 在我的情况下,我添加了字符串500k大小,然后开始另一个活动 . 它始终因此异常而失败 . 我避免使用活动的静态变量在活动之间共享数据 - 您不必将它们发送到Intent然后从中拉出来 .

    我有什么:

    String html = new String();//some string of 500K data.
    Intent intent = new Intent(MainActivity.this, PageWebView.class);
    //this is workaround - I just set static variable and then access it from another    activity.
    MainActivity.htmlBody = timelineDb.getHTMLBodyForTweet(tweet);
    //This line was present and it actually failed with the same exception you had.
    //intent.putExtra("com.gladimdim.offtie.webview", html);
    
  • 0

    这不是一个明确的答案,但它可能会揭示 TransactionTooLargeException 的原因并帮助查明问题 .

    虽然大多数答案都涉及大量传输的数据,但我看到在重度滚动和缩放以及重复打开ActionBar微调器菜单后偶然抛出此异常 . 点击操作栏时会发生崩溃 . (这是一个自定义 Map 应用程序)

    传递的唯一数据似乎是从“输入调度程序”到应用程序的触摸 . 我认为在“事务缓冲区”中这不可能合理地接近1 mb .

    我的应用程序运行在四核1.6 GHz设备上,使用3个线程进行重载,为UI线程保留一个核心 . 此外,该应用程序使用android:largeHeap,剩下10 MB未使用的堆,剩下100 MB的空间来增加堆 . 所以我不会说这是一个资源问题 .

    崩溃总是紧接着这些行:

    W/InputDispatcher( 2271): channel ~ Consumer closed input channel or an error occurred.  events=0x9
    E/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
    

    深入研究android的源代码,找到以下几行:

    框架/碱/核心/ 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 .

    这时我没有解决问题,但如果我发现有用的东西,我会更新这个答案 .

    update: 原来我的代码泄露了一些文件描述符,其数量在linux中最大化(通常为1024),这似乎触发了异常 . 所以这毕竟是一个资源问题 . 我通过打开 /dev/zero 1024次来验证这一点,这导致UI相关操作中出现各种奇怪的异常,包括上面的例外,甚至包括一些SIGSEGV . 显然无法打开文件/套接字并不是在整个Android中非常干净地处理/报告的内容 .

  • 1

    尝试使用 EventBusContentProvider 之类的解决方案 .

    如果您处于相同的过程(通常是您的所有活动),请尝试使用 EventBus ,因为在进程中数据交换不需要有点缓冲,因此您不必担心您的数据太大 . (你可以使用方法调用确实传递数据,而EventBus隐藏了丑陋的东西)以下是详细信息:

    // one side
    startActivity(intentNotTooLarge);
    EventBus.getDefault().post(new FooEvent(theHugeData));
    
    // the other side
    @Subscribe public void handleData(FooEvent event) { /* get and handle data */ }
    

    如果Intent的双方不在同一个进程中,请尝试 ContentProvider .


    TransactionTooLargeException

    Binder交易失败,因为它太大了 . 在远程过程调用期间,调用的参数和返回值将作为存储在Binder事务缓冲区中的Parcel对象进行传输 . 如果参数或返回值太大而不适合事务缓冲区,则调用将失败并抛出TransactionTooLargeException .

  • 0

    如果您需要调查导致崩溃的Parcel,您应该考虑尝试TooLargeTool .

    (我根据接受的答案发现这是@Max Spencer的评论,这对我的情况很有帮助 . )

  • 0

    我从Android Espresso测试中的Stackoverflow错误中获得了TransactionTooLargeException . 当我为我的应用程序取消Logcat过滤器时,我在日志中找到了stackoverflow错误堆栈跟踪 .

    我猜测Espresso在尝试处理非常大的异常堆栈跟踪时导致了TransactionTooLargeException .

  • 0

    将其添加到您的活动中

    @Override
    protected void onSaveInstanceState(Bundle oldInstanceState) {
        super.onSaveInstanceState(oldInstanceState);
        oldInstanceState.clear();
    }
    

    它对我有用,希望它也会对你有所帮助

  • 0

    对我来说,这也是 FragmentStatePagerAdapter ,但是压倒性的 saveState() 无效 . 以下是我修复它的方法:

    调用 FragmentStatePagerAdapter 构造函数时,在类中保留单独的片段列表,并添加一个方法来删除片段:

    class PagerAdapter extends FragmentStatePagerAdapter {
        ArrayList<Fragment> items;
    
        PagerAdapter(ArrayList<Fragment> frags) {
            super(getFragmentManager()); //or getChildFragmentManager() or getSupportFragmentManager()
            this.items = new ArrayList<>();
            this.items.addAll(frags);
        }
    
        public void removeFragments() {
            Iterator<Fragment> iter = items.iterator();
    
            while (iter.hasNext()) {
                Fragment item = iter.next();
                    getFragmentManager().beginTransaction().remove(item).commit();
                    iter.remove();
                }
                notifyDataSetChanged();
            }
        }
        //...getItem() and etc methods...
    }
    

    然后在 Activity 中,保存 ViewPager 位置并在重写的 onSaveInstanceState() 方法中调用 adapter.removeFragments()

    private int pagerPosition;
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //save other view state here
        pagerPosition = mViewPager.getCurrentItem();
        adapter.removeFragments();
    }
    

    最后,在重写的 onResume() 方法中,如果适配器不是 null ,则重新实例化该适配器 . (如果它是 null ,那么 Activity 是第一次打开,或者在应用程序被Android杀死后, onCreate 将执行适配器创建 . )

    @Override
    public void onResume() {
        super.onResume();
        if (adapter != null) {
            adapter = new PagerAdapter(frags);
            mViewPager.setAdapter(adapter);
            mViewPager.setCurrentItem(currentTabPosition);
        }
    }
    
  • 0

    您已从 onSaveInstanceState 方法清除旧的InstanceState,它将运行良好 . 我正在使用 FragmentStatePagerAdapter 作为我的viewpager,所以我将Override方法保留在我的父活动中以获得清晰的InstanceState .

    @Override
    protected void onSaveInstanceState(Bundle InstanceState) {
                 super.onSaveInstanceState(InstanceState);
                 InstanceState.clear();
    }
    

    我从这里找到了这个解决方案android.os.TransactionTooLargeException on Nougat

相关问题