得到了android.os.TransactionTooLargeException,据说是因为
“当同时通过 Parcels 传输过多数据时,会发生此异常。底层 Binder 事务缓冲区有一个有限的固定大小,目前为 1Mb,由该进程正在进行的所有事务共享。因此,当有许多事务正在进行时,即使大多数单个事务的大小适中,也可能会引发此异常。”</p>
android.os.TransactionTooLargeException: data parcel size 593484 bytes
at android.os.BinderProxy.transactNative(Binder.java)
at android.os.BinderProxy.transact(Binder.java:628)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:4132)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:4159)
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:6692)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
在它崩溃的时候,日志显示 mainActivity 启动 onSaveInstanceState() 并且它还包含一些片段。
583 | 04:46:32:173 (UTC) | MainActivity:onSaveInstanceState()
584 | 04:46:32:174 (UTC) | DataListFragment:onSaveInstanceState()
585 | 04:46:32:174 (UTC) | DrawerFragment:onSaveInstanceState()
586 | 04:46:32:174 (UTC) | DataContainerFragment:onSaveInstanceState()
587 | 04:46:32:174 (UTC) | DataDetailsFragment:onSaveInstanceState()
588 | 04:46:32:175 (UTC) | DataDetailsFragment:onSaveInstanceState()
589 | 04:46:32:175 (UTC) | DataDetailsFragment:onSaveInstanceState()
mainActivity 有一个 Drawer 和一个列表片段,当单击列表项时,会打开一个容器片段,该容器片段具有一个 viewPage 并包含三个详细信息片段。
看起来累积的数据已经超过了 Binder 的 1 meg 限制。
在他们的 onSaveInstanceState() 调用中仔细查看了所有片段保存的数据,它们都很小(int、boolean 等),加起来不到几 k,比如说 < 10k。
还查看了所有片段的布局文件,其中使用了 LiniearLayout、TextView、ImageView、WebView 等。并做了一个日志来查看 android View 可能保存的数据。
日志显示所有这些片段的 Views 总共可以节省不到 30k。
所以不知道这个“data parcel size 593484 bytes”是从哪里来的。
或者必须有一些其他数据android系统也在保存(?)。
有没有办法找出或转储“底层 Binder 事务缓冲区”数据以查看它们可能来自什么?有谁知道 android 对 WebView 所说的数据是什么(或如何找到)?
===
扩展视图来做日志,类似的用于片段中使用的其他视图
public class LogLinearLayout extends LinearLayout {
public LogLinearLayout(Context context) {
super(context);
}
public LogLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LogLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
for (int i = 0; i < container.size()-1; i++) {
Parcelable val = (Parcelable)container.get(i);
byte[] bytes = val != null ? marshall(val) : null;
String parcelByte = (bytes != null) ? "bytes.length:"+bytes.length : ("val==null");
if(bytes != null) {
//Log container level the bytes.length
}
}
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable pVal = super.onSaveInstanceState();
byte[] bytes = pVal != null ? marshall(pVal) : null;
String parcelByte = (bytes != null) ? "bytes.length:"+bytes.length : ("val==null");
if (bytes != null) {
//Log the bytes.length of this view
}
return pVal;
}
byte[] marshall(Parcelable parceable) {
Parcel parcel = Parcel.obtain();
parceable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
}