错误

最近将某个老项目升级到AndroidX,并且在将minSdk由19提升至24,targetSdk由23提升至28后,在某个数据量较大的场景出现了上述错误。
原因
该问题出现在有一个界面跳转到另一个界面时,大概含义就是传递的数据量过大,超过了限制。分析抛出的原因或条件,查看源码android_util_binder.cpp,查看系统层在什么情况下会抛出TransactionTooLargeException可知在binder驱动处理失败后,如果传输的parcel体积超过200kb,则会抛出TransactionTooLargeException,因此引发该问题的原因是binder调用传输的数据太大导致,问题分析重点应侧重binder数据传输。
解决
- 查看代码后发现,项目中在跳转时并未携带过多数据
1 2 3 4 5 6
| 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);
|
其中
1
| editViewModel.getFieldType()
|
1
| editViewModel.getValue()
|
以及
都是String类型的数据,并且数据长度都不大。 综合实际排错过程中的操作,只有在一个内嵌的fragment数据加载时才会出现上述错误,那我们先去fragment中看下:
1 2 3 4 5 6 7 8 9 10 11
| @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干掉再说
1 2 3 4 5 6 7 8 9
| @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
- 那么说明还有其他的地方有大量数据被带入到跳转时候的
binder中。 回到先前跳转的地方,我们发现startActivityForResult的地方居然是用的fragment,原来在这儿呢,看到上面的context直接就是一个activity引用,直接使用context.startActivityForResult,果然重新验证后没有出现数据传递超过限制的问题了,看来问题就在这个fragment中。
- 来到这个
fragment中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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方法中,我这里是自己定义的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @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(); } }
|

- 改完后发现影响了其他功能

原来项目中针对fragment专门处理了onActivityResult,导致重新进入的时候Bundle中的数据获取不到引起了其他的错误。
最后,直接在需要传值的地方,将数据传递给成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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方法直接赋值
1 2 3
| public void setModels(List<TestDetectionEditViewModel> models){ this.models = models; }
|
总结
处理TransactionTooLargeException的根本还是要针对数据传输做优化,要么使用类似EventBus的方法,要么使用成员变量直接赋值,避开通过Bundle传值这个坑。