BUG分析
android.os.TransactionTooLargeException: data parcel size 1167560 bytes
一般情况下看到这个BUG都会想到的是Intent传输数据过大了,Intent的数据过大是会导致TransactionTooLargeException
的表现,但是如果把这个异常完全归结于Intent就有点问题了,因为TransactionTooLargeException
不止会因为Intent传输数据过大了,在某些不是使用Intent的情况下依然会出这样的bug
真的只有Intent传值才会有问题吗,我们通过Intent看问题的本质
Intent携带信息的大小其实是受Binder
限制。数据以Parcel对象的形式存放在Binder传递缓存中。如果数据或返回值比传递buffer大,则此次传递调用失败并抛出TransactionTooLargeException异常。
Intent传值最大真的是1MB吗
Binder传递缓存有一个限定大小,通常是1Mb
。
但同一个进程中所有的传输共享缓存空间。多个地方在进行传输时,即时它们各自传输的数据不超出大小限制,TransactionTooLargeException异常也可能会被抛出。在使用Intent传递数据时,1Mb并不是安全上限。因为Binder中可能正在处理其它的传输工作。不同的机型和系统版本,这个上限值也可能会不同。在其它地方,例如onSaveInstanceState(@NonNull Bundle outState),也可能会遇到与Binder有关的类似问题。
通过toolargetool分析解决TransactionTooLargeException
我们知道了问题的本质是Binder引起的,而引起TransactionTooLargeException
不止是在Intent也可能是onSaveInstanceState(@NonNull Bundle outState)
,特别是onSaveInstanceState其实你没有使用他不代表他本身没有存储,当你遇到一个未知情况引起TransactionTooLargeException
的时候,你需求的toolargetool
来帮你解决问题
分析工具 toolargetool
地址:https://github.com/guardian/toolargetool
这是专门分析TransactionTooLargeException的工具
(1)增加 maven { url 'https://dl.bintray.com/guardian/android' } 在项目中的build.gradle
allprojects {
repositories {
jcenter()
...
maven { url 'https://dl.bintray.com/guardian/android' }
}
}
(2)增加 implementation 'com.gu.android:toolargetool:0.2.1@aar' 在你检测问题 module下的build.gradle:
dependencies {
...
implementation 'com.gu.android:toolargetool:0.2.1@aar'
//implementation 'com.gu.android:toolargetool:0.1.6@aar' // if you don't use AndroidX in your project
}
(3)在Application.onCreate方法里面增加
TooLargeTool.startLogging(this);
(4)在你要检查的类里面引入package
import com.gu.toolargetool.TooLargeTool;
(5)监视logcat输出,查看哪些组件正在向事务缓冲区写入大量数据以及何时写入
可以使用命令进行过滤:
$ adb logcat -s TooLargeTool
最终我们的过滤日志发现
12-02 16:35:33.087 16961 16961 D TooLargeTool: LivePlayerPageActivity.onSaveInstanceState wrote: Bundle131394213 contains 5 keys and measures 19.0 KB when serialized as a Parcel
12-02 16:35:33.087 16961 16961 D TooLargeTool: * android:viewHierarchyState = 1.0 KB
12-02 16:35:52.402 16961 16961 D TooLargeTool: LivePlayerPageActivity.onSaveInstanceState wrote: Bundle140574781 contains 5 keys and measures 57.8 KB when serialized as a Parcel
12-02 16:35:52.402 16961 16961 D TooLargeTool: * android:viewHierarchyState = 14.2 KB
12-02 16:36:23.626 16961 16961 D TooLargeTool: LivePlayerPageActivity.onSaveInstanceState wrote: Bundle216803432 contains 5 keys and measures 83.2 KB when serialized as a Parcel
12-02 16:36:23.626 16961 16961 D TooLargeTool: * android:viewHierarchyState = 37.2 KB
12-02 16:37:12.587 16961 16961 D TooLargeTool: LivePlayerPageActivity.onSaveInstanceState wrote: Bundle91071570 contains 5 keys and measures 118.5 KB when serialized as a Parcel
12-02 16:37:12.587 16961 16961 D TooLargeTool: * android:viewHierarchyState = 76.1 KB
12-02 16:37:37.113 16961 16961 D TooLargeTool: LivePlayerPageActivity.onSaveInstanceState wrote: Bundle45092331 contains 5 keys and measures 166.8 KB when serialized as a Parcel
12-02 16:37:37.113 16961 16961 D TooLargeTool: * android:viewHierarchyState = 122.2 KB
12-02 16:39:31.786 16961 16961 D TooLargeTool: LivePlayerPageActivity.onSaveInstanceState wrote: Bundle267655365 contains 5 keys and measures 202.2 KB when serialized as a Parcel
12-02 16:39:31.786 16961 16961 D TooLargeTool: * android:viewHierarchyState = 159.7 KB
这问题是使用ViewPager2实现纵滑直播间,在特定情况下出现的TransactionTooLargeException
,在特定下情况再次滑动直播间android:viewHierarchyState 的值一直是增加的
最终导致超限引起TransactionTooLargeException
既然知道问题所在了,但是我没有找到为什么viewHierarchyState会一直增加,源码中对这个方法也没有描述,不知其含义 所以我们选择了一种无可奈何的解决办法让ViewPager2不再保存
在xml中增加android:saveEnabled="false"
,这不是一个最完美的办法 但是目前在一个未知问题下是解决我们现在问题的一种方式,因为我们的页面不涉及横竖屏切换这样的操作.
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="0dp"
android:layout_height="0dp"
android:saveEnabled="false" />
网友评论