Android 如何处理TransactionTooLargeException
我得到了一个Android 如何处理TransactionTooLargeException,android,exception,Android,Exception,我得到了一个TransactionTooLargeException。不可复制。文件上写着 活页夹事务失败,因为它太大 在远程过程调用期间,参数和调用的返回值作为存储在活页夹事务缓冲区中的地块对象进行传输。如果参数或返回值太大,无法放入事务缓冲区,则调用将失败,并引发TransactionTooLargeException 当远程过程调用引发TransactionTooLargeException时,有两种可能的结果。客户端无法将其请求发送到服务(很可能是因为参数太大而无法放入事务缓冲区),或
TransactionTooLargeException
。不可复制。文件上写着
活页夹事务失败,因为它太大
在远程过程调用期间,参数和调用的返回值作为存储在活页夹事务缓冲区中的地块对象进行传输。如果参数或返回值太大,无法放入事务缓冲区,则调用将失败,并引发TransactionTooLargeException
当远程过程调用引发TransactionTooLargeException时,有两种可能的结果。客户端无法将其请求发送到服务(很可能是因为参数太大而无法放入事务缓冲区),或者服务无法将其响应发送回客户端(很可能是因为返回值太大而无法放入事务缓冲区)
所以我在某个地方传递或接收超过未知极限的参数。在哪里
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,我在三星S3上也遇到了这个例外。 我怀疑有两个根本原因
问题已经解决。所以对我们来说,我们试图通过AIDL接口将太大的对象发送到远程服务。事务大小不能超过1MB。请求被分解成512KB的独立块,并通过接口一次发送一个。我知道一个残酷的解决方案,但它是Android:(我遇到了这个问题,我发现当服务和应用程序之间交换大量数据时,(这涉及到传输大量缩略图).实际上,数据大小约为500kb,IPC事务缓冲区大小设置为1024KB。我不确定为什么它超过了事务缓冲区 当您通过intent extras传递大量数据时,也会发生这种情况 当您的应用程序中出现此异常时,请分析您的代码
我不知道如何做到这一点,但是,不要查询android,它可能会返回大量数据:-)请确保不要将大量的目标数据放入其中。在我的例子中,我添加了500k大小的字符串,然后开始另一项活动。它总是因为这个例外而失败。通过使用活动的静态变量,我避免了在活动之间共享数据——您不必将它们发送给Intent然后再从中提取 我所拥有的:
String html = new String();//some string of 500K data.
Intent intent = new Intent(MainActivity.this, PageWebView.class);
//this is workaround - I just set static variable and then access it from another activity.
MainActivity.htmlBody = timelineDb.getHTMLBodyForTweet(tweet);
//This line was present and it actually failed with the same exception you had.
//intent.putExtra("com.gladimdim.offtie.webview", html);
这不是一个确定的答案,但它可能会揭示出
TransactionTooLargeException
的原因,并有助于找出问题所在
尽管大多数答案都涉及传输的大量数据,但我看到,在频繁滚动和缩放并反复打开ActionBar微调器菜单后,会意外抛出此异常。碰撞发生在轻敲操作杆时。(这是一个自定义映射应用程序)
传递的唯一数据似乎是从“输入调度器”到应用程序的触摸。我认为这在“事务缓冲区”中不可能合理地达到接近1MB
我的应用程序运行在一个四核1.6GHz设备上,使用3个线程进行重升级,为UI线程保留一个内核。此外,该应用程序使用android:largeHeap,还剩下10 mb未使用的堆,还有100 mb的空间来扩展堆。所以我不会说这是一个资源问题
碰撞前始终紧跟着以下几行:
W/InputDispatcher( 2271): channel ~ Consumer closed input channel or an error occurred. events=0x9
E/InputDispatcher( 2271): channel ~ Channel is unrecoverably broken and will be disposed!
E/JavaBinder(28182): !!! FAILED BINDER TRANSACTION !!!
它们不一定按那个顺序打印,但(据我所查)发生在同一毫秒
为了清楚起见,堆栈跟踪本身与问题中的相同:
E/AndroidRuntime(28182): java.lang.RuntimeException: Adding window failed
..
E/AndroidRuntime(28182): Caused by: android.os.TransactionTooLargeException
深入研究android one的源代码可以发现以下几行代码:
W/InputDispatcher( 2271): channel ~ Consumer closed input channel or an error occurred. events=0x9
E/InputDispatcher( 2271): channel ~ Channel is unrecoverably broken and will be disposed!
E/JavaBinder(28182): !!! FAILED BINDER TRANSACTION !!!
frameworks/base/core/jni/android\u util\u Binder.cpp:
case FAILED_TRANSACTION:
ALOGE("!!! FAILED BINDER TRANSACTION !!!");
// TransactionTooLargeException is a checked exception, only throw from certain methods.
// FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
// but it is not the only one. The Binder driver can return BR_FAILED_REPLY
// for other reasons also, such as if the transaction is malformed or
// refers to an FD that has been closed. We should change the driver
// to enable us to distinguish these cases in the future.
jniThrowException(env, canThrowRemoteException
? "android/os/TransactionTooLargeException"
: "java/lang/RuntimeException", NULL);
对我来说,这听起来像是我正在使用这个未记录的特性,其中事务失败的原因除了事务正在处理之外。他们应该将其命名为TransactionToolArgeorNotherReasonException
在这个时候我没有解决这个问题,但如果我发现一些有用的东西,我会更新这个答案
更新:结果是我的代码泄漏了一些文件描述符,这些描述符的数量在linux中是最大的(通常是1024个),这似乎触发了异常。所以这毕竟是一个资源问题。我通过打开/dev/zero
1024次验证了这一点,这导致了UI相关操作中的各种奇怪异常,包括上面的异常,甚至一些SIGSEGV。显然没有打开f
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.snacks_layout, container); //<-- notice the absence of the false argument
return rootView;
}
View rootView = inflater.inflate(R.layout.softs_layout, container, false);
try {
count = provider.bulkInsert(uri, contentValueses);
} catch (TransactionTooLarge e) {
int half = contentValueses.length/2;
count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, 0, half));
count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, half, contentValueses.length));
}
E/ActivityThread: App sent too much data in instance state, so it was ignored
android.os.TransactionTooLargeException: data parcel size 713856 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
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:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 713860 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3737)
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:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: android.os.TransactionTooLargeException: data parcel size 713860 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
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:6044)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
@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;
}
@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;
}
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;
}
}
@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() );
}
class PagerAdapter extends FragmentStatePagerAdapter {
ArrayList<Fragment> items;
PagerAdapter(ArrayList<Fragment> frags) {
super(getFragmentManager()); //or getChildFragmentManager() or getSupportFragmentManager()
this.items = new ArrayList<>();
this.items.addAll(frags);
}
public void removeFragments() {
Iterator<Fragment> iter = items.iterator();
while (iter.hasNext()) {
Fragment item = iter.next();
getFragmentManager().beginTransaction().remove(item).commit();
iter.remove();
}
notifyDataSetChanged();
}
}
//...getItem() and etc methods...
}
private int pagerPosition;
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//save other view state here
pagerPosition = mViewPager.getCurrentItem();
adapter.removeFragments();
}
@Override
public void onResume() {
super.onResume();
if (adapter != null) {
adapter = new PagerAdapter(frags);
mViewPager.setAdapter(adapter);
mViewPager.setCurrentItem(currentTabPosition);
}
}
dest=Parcel.obtain();
// one side
startActivity(intentNotTooLarge);
EventBus.getDefault().post(new FooEvent(theHugeData));
// the other side
@Subscribe public void handleData(FooEvent event) { /* get and handle data */ }
@Override
protected void onSaveInstanceState(Bundle outState) {
// super.onSaveInstanceState(outState);
}
@Override
protected void onSaveInstanceState(Bundle InstanceState) {
super.onSaveInstanceState(InstanceState);
InstanceState.clear();
}
android:largeHeap="true"
public static Bitmap bitmap_image;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
bitmap_image=mybitmap;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Bitmap mybitmap=first.bitmap_image;
}
@Override
protected void onSaveInstanceState(Bundle oldInstanceState) {
super.onSaveInstanceState(oldInstanceState);
oldInstanceState.clear();
}
private ArrayList<SearchResult> mSearchResults;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getArguments() != null && getArguments().getSerializable("SearchResults") != null) {
mSearchResults = (ArrayList) getArguments().getSerializable("SearchResults");
}
}
private void onSearchResultsObtained(ArrayList<SearchResult> pSearchResults) {
// Because mSearchResults points to the same location in memory as the fragment's arguments
// this will also increase the size of the arguments!
mSearchResults.addAll(pSearchResults);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getArguments() != null && getArguments().getSerializable("SearchResults") != null) {
// Copy value of array instead of reference
mSearchResults = new ArrayList((ArrayList) getArguments().getSerializable("SearchResults"));
}
}
class SavedInstanceFragment : Fragment() {
// This map will hold bundles from different sources (tag -> bundle).
private lateinit var bundleMap: HashMap<String, Bundle?>
// This method is only called once for this fragment.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
bundleMap = HashMap()
}
fun pushData(key: String, bundle: Bundle): SavedInstanceFragment {
if (bundleMap[key] == null) {
bundleMap[key] = bundle
} else {
bundleMap[key]!!.putAll(bundle)
}
return this
}
fun popData(key: String): Bundle? {
val data = bundleMap[key]
bundleMap[key] = null
return data
}
fun removeData(key: String) {
bundleMap.remove(key)
}
companion object {
private val TAG = SavedInstanceFragment::class.java.simpleName
// Create the fragment with this method in `onCreate()` of an activity.
// Then you can get this fragment with this method again.
fun getInstance(fragmentManager: FragmentManager): SavedInstanceFragment {
var out = fragmentManager.findFragmentByTag(TAG) as SavedInstanceFragment?
if (out == null) {
out = SavedInstanceFragment()
fragmentManager.beginTransaction().add(out, TAG).commit()
}
return out
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity)
if (savedInstanceState == null) {
SavedInstanceFragment.getInstance(supportFragmentManager)
}
...
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bundle = if (savedInstanceState == null) {
// Remove old data in order not to show wrong information.
SavedInstanceFragment.getInstance(activity!!.supportFragmentManager).removeData(TAG)
null
} else {
SavedInstanceFragment.getInstance(activity!!.supportFragmentManager).popData(TAG)
}
(bundle ?: arguments)?.run { // I access 'bundle' or 'arguments', depending if it is not first or first call of 'onCreate()'.
token = getString(ARG_TOKEN)!!
id = getInt(ARG_ID)
items = getParcelableArrayList(ARG_ITEMS)
}
}
override fun onSaveInstanceState(outState: Bundle) {
// Create a copy of savedInstanceState and push to the retain-instance fragment.
val bundle = (outState.clone() as Bundle).apply {
putString(ARG_TOKEN, token)
putInt(ARG_ID, id)
putParcelableArrayList(ARG_ITEMS, items)
}
SavedInstanceFragment.getInstance(activity!!.supportFragmentManager).pushData(TAG, bundle)
arguments?.clear() // Avoids an exception "java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size xxxxxxx bytes".
super.onSaveInstanceState(outState)
}
companion object {
private val TAG = YourFragment::class.java.simpleName
private const val ARG_TOKEN = "ARG_TOKEN"
private const val ARG_ID = "ARG_ID"
private const val ARG_ITEMS = "ARG_ITEMS"
fun newInstance(token: String, id: Int, items: ArrayList<Item>?) =
YourFragment().apply {
arguments = Bundle().apply {
putString(ARG_TOKEN, token)
putInt(ARG_ID, id)
putParcelableArrayList(ARG_ITEMS, items)
}
}
}
class SecondFragment : BaseFragment() {
lateinit var myContent: MyContent
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
myContent = arguments?.getParcelable("mycontent")
arguments?.clear()
}
val fragments = sportFragmentManager.fragments
val transaction = sportFragmentManager.beginTransaction()
for (frag in fragments){
transaction.remove(frag)
}
transaction.commitAllowingStateLoss()
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]
public final int MAX_BUNDLE_SIZE = 300;
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
long bundleSize = getBundleSize(outState);
if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
outState.clear();
}
}
private long getBundleSize(Bundle bundle) {
long dataSize;
Parcel obtain = Parcel.obtain();
try {
obtain.writeBundle(bundle);
dataSize = obtain.dataSize();
} finally {
obtain.recycle();
}
return dataSize;
}