我得到了一个TransactionTooLargeException。无法复制的。文件里说
The Binder transaction failed because it was too large.
During a remote procedure call, the arguments and the return value of the call are transferred as Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException will be thrown.
...
There are two possible outcomes when a remote procedure call throws TransactionTooLargeException. Either the client was unable to send its request to the service (most likely if the arguments were too large to fit in the transaction buffer), or the service was unable to send its response back to the client (most likely if the return value was too large to fit in the transaction buffer).
...
在某个地方,我传递或接收的参数超出了未知的限制。在哪里?
stacktrace没有显示任何有用的东西:
java.lang.RuntimeException: Adding window failed
at android.view.ViewRootImpl.setView(ViewRootImpl.java:548)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
... 16 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
这似乎和观点有关?这与远程过程调用有什么关系?
可能重要的是:Android版本:4.0.3,设备:HTC One X
问题通过以下方式解决:
Bundle bundle = new Bundle();
bundle.putSerializable("data", bigdata);
...
CacheHelper.saveState(bundle,"DATA");
Intent intent = new Intent(mActivity, AActivity.class);
startActivity(intent, bb);// do not put data to intent.
In Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
Bundle bundle = CacheHelper.getInstance().loadState(Constants.DATA);
if (bundle != null){
Intent intent = getIntent();
intent.putExtras(bundle);
}
getIntent().getExtra(..);
....
}
@Override
protected void onDestroy() {
super.onDestroy();
CacheHelper.clearState("DATA");
}
public class CacheHelper {
public static void saveState(Bundle savedInstanceState, String name) {
Bundle saved = (Bundle) savedInstanceState.clone();
save(name, saved);
}
public Bundle loadState(String name) {
Object object = load(name);
if (object != null) {
Bundle bundle = (Bundle) object;
return bundle;
}
return null;
}
private static void save(String fileName, Bundle object) {
try {
String path = StorageUtils.getFullPath(fileName);
File file = new File(path);
if (file.exists()) {
file.delete();
}
FileOutputStream fos = new FileOutputStream(path, false);
Parcel p = Parcel.obtain(); //creating empty parcel object
object.writeToParcel(p, 0); //saving bundle as parcel
//parcel.writeBundle(bundle);
fos.write(p.marshall()); //writing parcel to file
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static Bundle load(String fileName) {
try {
String path = StorageUtils.getFullPath(fileName);
FileInputStream fis = new FileInputStream(path);
byte[] array = new byte[(int) fis.getChannel().size()];
fis.read(array, 0, array.length);
Parcel parcel = Parcel.obtain(); //creating empty parcel object
parcel.unmarshall(array, 0, array.length);
parcel.setDataPosition(0);
Bundle out = parcel.readBundle();
out.putAll(out);
fis.close();
parcel.recycle();
return out;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void clearState(Activity ac) {
String name = ac.getClass().getName();
String path = StorageUtils.getFullPath(name);
File file = new File(path);
if (file.exists()) {
file.delete();
}
}
}
TransactionTooLargeException已经困扰我们大约4个月了,我们终于解决了这个问题!
发生的是我们在ViewPager中使用FragmentStatePagerAdapter。用户将翻页并创建100多个片段(这是一个阅读应用程序)。
虽然我们在destroyItem()中正确地管理片段,但在android中
FragmentStatePagerAdapter的实现有一个bug,它保持了对以下列表的引用:
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
当Android的FragmentStatePagerAdapter尝试保存状态时,它将调用该函数
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
正如您所看到的,即使您正确地管理FragmentStatePagerAdapter子类中的片段,基类仍然会存储一个片段。SavedState用于创建的每个片段。TransactionTooLargeException会在数组被转储到parcelableArray时发生,而操作系统不希望它有100+项。
因此,我们的解决方案是重写saveState()方法,不为“状态”存储任何东西。
@Override
public Parcelable saveState() {
Bundle bundle = (Bundle) super.saveState();
bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
return bundle;
}
我发现了这个问题的根本原因(我们得到了“添加窗口失败”和文件描述符泄漏mvds说)。
Android 4.4的BitmapFactory.decodeFileDescriptor()有一个bug。
只有当BitmapOptions的inPurgeable和inInputShareable设置为true时才会发生。这在与文件交互的许多地方造成了许多问题。
注意,该方法也是从MediaStore.Images.Thumbnails.getThumbnail()调用的。
通用图像加载器受此问题影响。毕加索和格莱德似乎没有受到影响。
https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020
有时活动包括一些片段时,活动需要完全重新创建片段内容,
如果sportFragmentManager.fragments没有清晰的历史片段
val fragments = sportFragmentManager.fragments
val transaction = sportFragmentManager.beginTransaction()
for (frag in fragments){
transaction.remove(frag)
}
transaction.commitAllowingStateLoss()
几次重新创建片段活动将发生(调试使用tooLargeTool)
W/ActivityStopInfo: Bundle stats:
W/ActivityStopInfo: android:viewHierarchyState [size=2304]
W/ActivityStopInfo: android:views [size=2256]
W/ActivityStopInfo: android:support:fragments [size=519072]
W/ActivityStopInfo: PersistableBundle stats:
W/ActivityStopInfo: [null]