我得到了一个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
有这么多地方TransactionTooLargeException可以发生——这里是Android 8的一个新情况——当有人开始输入EditText时,如果内容太大,就会崩溃。
它与AutoFillManager (API 26中新增)和StartSessionLocked()中的以下代码相关:
mSessionId = mService.startSession(mContext.getActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, mContext.getOpPackageName());
如果我理解正确的话,这调用了自动填充服务——在绑定器中传递AutofillManagerClient。当EditText有很多内容时,它似乎会引起TTLE。
在EditText的xml布局声明中添加android:importantForAutofill="noExcludeDescendants"。或者在代码中:
EditText et = myView.findViewById(R.id.scriptEditTextView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
et.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
}
第二种糟糕的解决方法可能是重写performClick()和onWindowFocusChanged()方法来捕获TextEdit子类本身的错误。但我不认为这是明智的……
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;
}
我遇到过这个问题,我发现当服务和应用程序之间交换大量数据时(这涉及传输大量的缩略图)。实际上数据大小在500kb左右,IPC事务缓冲区大小设置为1024KB。我不确定为什么它超过了事务缓冲区。
当您通过intent extras传递大量数据时,也会发生这种情况
当您在应用程序中遇到此异常时,请分析您的代码。
您是否在服务和应用程序之间交换了大量数据?
使用intent共享海量数据,(例如用户从gallery共享中选择大量文件按share,所选文件的uri将使用intent传输)
从服务接收位图文件
等待android返回大量数据(例如,当用户安装了大量应用程序时,getInstalledApplications())
使用applyBatch()处理大量未决操作
当你得到这个异常时如何处理
如果可能的话,将大操作拆分为小块,例如,调用applyBatch()时不要使用1000个操作,而是每个操作使用100个。
服务和应用之间不交换大数据(>1MB)
我不知道怎么做,但是,不要查询android,它可以返回巨大的数据:-)
此异常通常在应用程序被发送到后台时抛出。
因此,我决定使用数据片段模式来完全绕过onSavedInstanceState生命周期。我的解决方案还处理复杂的实例状态并尽快释放内存。
首先,我创建了一个简单的片段来存储数据:
package info.peakapps.peaksdk.logic;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
/**
* A neat trick to avoid TransactionTooLargeException while saving our instance state
*/
public class SavedInstanceFragment extends Fragment {
private static final String TAG = "SavedInstanceFragment";
private Bundle mInstanceBundle = null;
public SavedInstanceFragment() { // This will only be called once be cause of setRetainInstance()
super();
setRetainInstance( true );
}
public SavedInstanceFragment pushData( Bundle instanceState )
{
if ( this.mInstanceBundle == null ) {
this.mInstanceBundle = instanceState;
}
else
{
this.mInstanceBundle.putAll( instanceState );
}
return this;
}
public Bundle popData()
{
Bundle out = this.mInstanceBundle;
this.mInstanceBundle = null;
return out;
}
public static final SavedInstanceFragment getInstance(FragmentManager fragmentManager )
{
SavedInstanceFragment out = (SavedInstanceFragment) fragmentManager.findFragmentByTag( TAG );
if ( out == null )
{
out = new SavedInstanceFragment();
fragmentManager.beginTransaction().add( out, TAG ).commit();
}
return out;
}
}
然后在我的主活动上,我完全绕过了保存的实例周期,并将责任推迟到我的数据片段。不需要对片段本身使用这个,因为它们的状态会自动添加到Activity的状态中):
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
SavedInstanceFragment.getInstance( getFragmentManager() ).pushData( (Bundle) outState.clone() );
outState.clear(); // We don't want a TransactionTooLargeException, so we handle things via the SavedInstanceFragment
}
剩下的就是弹出保存的实例:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(SavedInstanceFragment.getInstance(getFragmentManager()).popData());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState( SavedInstanceFragment.getInstance( getFragmentManager() ).popData() );
}
详情:http://www.devsbedevin.net/avoiding-transactiontoolargeexception-on-android-nougat-and-up/