最近项目测试的时候遇到一个隐藏的bug,之前一直测试一直没有测出来,而且运行的时候不会报错,下面是bug描述:
11-16 17:07:51.301 12598-12598/com.hx.socialapp E/JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 520536)
11-16 17:07:51.326 12598-12598/com.hx.socialapp E/RongLog: [ RongExceptionHandler ] uncaughtException
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 520536 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:4050)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6436)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1113)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:974)
Caused by: android.os.TransactionTooLargeException: data parcel size 520536 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:626)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3908)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:4042)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6436)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1113)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:974)
刚开始看这个异常, 是在跳转页面的发现的,因为看不出是哪个activity,以为是跳转到另外一个界面的activity,.找了半天都没有解决.
后来检查了一下代码,发现都是代码: 传递的数据都是很小的,,根本不够512KB, 既然不会报这个异常,为啥他报这个异常呢?
后来自己重新仔仔细细检查了一下.原来是把一个String 当成bean给传递了,传递给下面的fragment又没有接,造成了,错误代码如下:
Bundle b = new Bundle();
ShopTypeCommodityFragment fragment = new ShopTypeCommodityFragment();
b.putInt("shopindex", i);
b.putSerializable("shopoffid", mShopList.get(i).getId());
b.putSerializable("shopoffline", (Serializable) mShopList);
fragment.setArguments(b);
/* Fragment fragment = ShopTypeCommodityFragment.getInstance(b);
//mFragmentList.add(fragment);*/
Log.i("onCreateView", "onCreateViewmShopIndexyyy " + mShopList.get(i).getId());
mFragmentList.add(fragment);
for (int i = 0; i < mShopList.size(); i++) {
Bundle b = new Bundle();
ShopTypeCommodityFragment fragment = new ShopTypeCommodityFragment();
b.putInt("shopindex", i);
b.putSerializable("shopoffline", (Serializable) mShopList);
fragment.setArguments(b);
/* Fragment fragment = ShopTypeCommodityFragment.getInstance(b);
//mFragmentList.add(fragment);*/
Log.i("onCreateView", "onCreateViewmShopIndexyyy " + mShopList.get(i).getId());
mFragmentList.add(fragment);
}
自己写代码写漏了,把String 给序列化传递.导致出现这个异常.
下面的部分还是网站总结比较好的一篇博客,贴到下面供大家参考:
这个问题没找到官方说明,针对网上的各种答案,自己实际测试了一下。
见参考文献1、2。
①我们构建一个1K的字符串;
②再构建ArrayList的字符串列表;
③用Intent.putStringArrayListExtra传递
我们知道1个char占2个字节,那么构建一个512的字符串就刚好1K了。
实测的时候发现512占了1040,于是减掉8个,取504个。
int size=504;
mStringBuilder=new StringBuilder(size);
for(int i=0;i<size;i++){
mStringBuilder.append("a");
}
//这个mString占1024bytes
mString=mStringBuilder.toString();
public void openActivity() {
try {
mIntent = new Intent(this, TestActivity2.class);
//这里要注意的,只有每次都add一个新的字符串,mStringList的大小才会线性变大,否则,指向的是同一个地址
//但是,即使指向同一个地址,在put的时候也是会出错的,原因,就是因为put要放入每一个值吧。
mStrngList.add(mStringBuilder.toString());
mIntent.putStringArrayListExtra("string_list", mStrngList);
Log.d("test", "put size:" + mStrngList.size());
startActivityForResult(mIntent, REQUEST_CODE_TEST);
}catch (Exception e){
e.printStackTrace();
}
}
//在这里在调用打开,就循环了
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK && requestCode==REQUEST_CODE_TEST && mContinue){
openActivity();
}
}
当mArrayList的size是509的时候,就闪退了。
有以下两张图。
可以看到508的时候
522936/1024=510.68
509的时候
523960/1024=511.68
虽然还没有到512,但我还是得出512的结论,原因是Intent的其他内容也要占内存,所以诱发闪退的原因应该是512.
改下测试代码
public void openActivity() {
try {
mIntent = new Intent(this, TestActivity2.class);
mStrngList.remove(0);
Log.d("test", "try put size:" + mStrngList.size());
mIntent.putStringArrayListExtra("string_list", mStrngList);
startActivityForResult(mIntent, REQUEST_CODE_TEST);
Log.d("test", "put success:" + mStrngList.size());
}catch (Exception e){
e.printStackTrace();
openActivity();
}
}
1018的时候闪退,1019时捕获异常。
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 1039780)
Caused by: android.os.TransactionTooLargeException: data parcel size 1039780 bytes
这个官方是有说明的,最在1M(见参考文献3),
上面的1039780/1024=1015.41,哈哈,不要在乎这些细节。
看下面2张图
1046536/1024=1022.01
1047560/1024=1023.01