Loading... ### 错误  > 最近将某个老项目升级到AndroidX,并且在将minSdk由19提升至24,targetSdk由23提升至28后,在某个数据量较大的场景出现了上述错误。 ### 原因 该问题出现在有一个界面跳转到另一个界面时,大概含义就是传递的数据量过大,超过了限制。分析抛出的原因或条件,查看源码android_util_binder.cpp,查看系统层在什么情况下会抛出TransactionTooLargeException可知在binder驱动处理失败后,如果传输的parcel体积超过200kb,则会抛出TransactionTooLargeException,因此引发该问题的原因是binder调用传输的数据太大导致,问题分析重点应侧重binder数据传输。 ### 解决 1. 查看代码后发现,项目中在跳转时并未携带过多数据 ```Java Intent intent = new Intent(context, TestDetectionEditTabInnerActivity.class); intent.putExtra(NavigationViewDataInitHelper.TYPE_CODE, editViewModel.getFieldType()); intent.putExtra(TestDetectionEditTabInnerActivity.RECORD_VALUE, editViewModel.getValue()); intent.putExtra(TestDetectionEditTabInnerActivity.PROJECT_NAME, editViewModel.getName()); intent.putExtra(NavigationViewDataInitHelper.FUNCTION_IDENTIFICATION, functionIdentification); fragment.startActivityForResult(intent, Constants.REQUEST_CODE); ``` 其中 ```Java editViewModel.getFieldType() ``` ```Java editViewModel.getValue() ``` ```Java editViewModel.getName() ``` 以及 ```Java functionIdentification ``` 都是`String`类型的数据,并且数据长度都不大。 综合实际排错过程中的操作,只有在一个内嵌的`fragment`数据加载时才会出现上述错误,那我们先去`fragment`中看下: ```Java @Override public Bundle createBundle(QFormViewModel viewModel, ExpandFormSchemaModel dataModel) { Bundle bundle = new Bundle(); bundle.putString(INTENT_SMART_INPUT_FRAGMENT_SOURCE, dataModel.getDataSource()); mParamValidators = dataModel.getParamValidators(); mDatasourceKey = dataModel.getDatasourceKey(); mJsonBody = dataModel.getJsonBody(); mListSource = dataModel.getListSource(); mFunctionIdentification = dataModel.getFunctionIdentification(); return bundle; } ``` 好家伙,先把这个bundle干掉再说 ```Java @Override public Bundle createBundle(QFormViewModel viewModel, ExpandFormSchemaModel dataModel) { mParamValidators = dataModel.getParamValidators(); mDatasourceKey = dataModel.getDatasourceKey(); mJsonBody = dataModel.getJsonBody(); mListSource = dataModel.getListSource(); mFunctionIdentification = dataModel.getFunctionIdentification(); return null; } ``` 重新编译运行,发现还是GG 2. 那么说明还有其他的地方有大量数据被带入到跳转时候的`binder`中。 回到先前跳转的地方,我们发现`startActivityForResult`的地方居然是用的`fragment`,原来在这儿呢,看到上面的`context`直接就是一个`activity`引用,直接使用```context.startActivityForResult```,果然重新验证后没有出现数据传递超过限制的问题了,看来问题就在这个`fragment`中。 3. 来到这个`fragment`中 ```Java public static TestDetectionEditTabFragment newInstance( List<TestDetectionEditViewModel> models, String recordId, String functionIdentification, String type, String projectName, String defaultValue) { Bundle args = new Bundle(); args.putParcelableArrayList(MODELS, (ArrayList<? extends Parcelable>) models); args.putString(RECORD_ID, recordId); args.putString(FUNCTION_IDENTIFICATION, functionIdentification); args.putString(TYPE, type); args.putString(PROJECT_NAME, projectName); args.putString(DEFAULT_VALUE, defaultValue); TestDetectionEditTabFragment fragment = new TestDetectionEditTabFragment(); fragment.setArguments(args); return fragment; } ``` 我们看到在静态方法中往`Bundle`中塞入了很多的数据,这些数据在先前`startActivityForResult`的时候就是作为引用`context`包含在`binder`中。 找到`Bundle`数据获取完的地方,对`Bundle`实施`clear`方法。一般是`onViewCreated`方法中,我这里是自己定义的方法。 ```Java @Override protected void iData(View view) { Bundle arguments = getArguments(); if (arguments != null) { models = arguments.getParcelableArrayList(MODELS); recordId = arguments.getString(RECORD_ID); functionIdentification = arguments.getString(FUNCTION_IDENTIFICATION); type = arguments.getString(TYPE); projectName = arguments.getString(PROJECT_NAME); defaultValue = arguments.getString(DEFAULT_VALUE); setAdapter(models); arguments.clear(); } } ```  4. 改完后发现影响了其他功能  原来项目中针对`fragment`专门处理了`onActivityResult`,导致重新进入的时候`Bundle`中的数据获取不到引起了其他的错误。 最后,直接在需要传值的地方,将数据传递给成员变量 ```Java public static TestDetectionEditTabFragment newInstance( List<TestDetectionEditViewModel> models, String recordId, String functionIdentification, String type, String projectName, String defaultValue) { Bundle args = new Bundle(); args.putString(RECORD_ID, recordId); args.putString(FUNCTION_IDENTIFICATION, functionIdentification); args.putString(TYPE, type); args.putString(PROJECT_NAME, projectName); args.putString(DEFAULT_VALUE, defaultValue); TestDetectionEditTabFragment fragment = new TestDetectionEditTabFragment(); fragment.setArguments(args); fragment.setModels(models); return fragment; } ``` 通过`set`方法直接赋值 ```Java public void setModels(List<TestDetectionEditViewModel> models){ this.models = models; } ``` ### 总结 > 处理`TransactionTooLargeException`的根本还是要针对数据传输做优化,要么使用类似`EventBus`的方法,要么使用成员变量直接赋值,避开通过`Bundle`传值这个坑。 最后修改:2022 年 01 月 21 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏