TransactionTooLargeExceptionで何をするか


239

を手に入れましたTransactionTooLargeException。再現できません。ドキュメントでそれは言う

バインダートランザクションが大きすぎるため、失敗しました。

リモートプロシージャコール中に、呼び出しの引数と戻り値は、バインダートランザクションバッファーに格納されたParcelオブジェクトとして転送されます。引数または戻り値が大きすぎてトランザクションバッファーに収まらない場合、呼び出しは失敗し、TransactionTooLargeExceptionがスローされます。

...

リモートプロシージャコールがTransactionTooLargeExceptionをスローする場合、2つの結果が考えられます。クライアントが要求をサービスに送信できなかったか(おそらく引数が大きすぎてトランザクションバッファーに収まらない場合)、またはサービスがクライアントに応答を送信できなかった(おそらく戻り値がトランザクションバッファーに収まらないほど大きい)。

...

だから、どこかで未知の制限を超える引数を渡したり受け取ったりしています。どこ?

スタックトレースは有用なものを何も示していません:

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


いいえ、しかし、私は再びそれを取得しませんでした。ライブアプリにエラートラッカーを用意して、約3週間で1回だけ取得します。少なくともそれは頻繁に起こるようには見えません。たぶん、Androidで問題を開く価値があるかもしれませんが...
Ixx

答えはありませんが、これにより確実にGalaxy S2がハードリセットされます。
Timmmm

今日、私のアプリケーションの1つでこれが発生しました。これも一度だけ、Galaxy S3で発生しました。これは、より強力なデバイスでしか理解できないように見えるのは興味深いことです。
danwms 2012

その例外はAPI 15、developer.android.com / reference / android / os /… に追加されました。マップをスクロールしながらMapViewでそれを再現しました。メモリが残っていないことがGCから書き込まれるまで(数分かかりました)
meh

トランザクションバッファはすべてのデバイスで1MBに制限されており、このバッファはすべてのトランザクションを古くします。したがって、デバイスがより強力になるほど、同時に実行できるトランザクションが増え、そのすべてが同じ1MBバッファを消費します。とはいえ、あなたの答えは答えではなくコメントです。
3c71 2013年

回答:


158

この問題が発生し、サービスとアプリケーションの間で大量のデータが交換されると、大量のサムネイルが転送されることがわかりました。実際のデータサイズは約500 kbで、IPCトランザクションバッファサイズは1024 KBに設定されています。トランザクションバッファーを超えた理由がわかりません。

これは、インテントエクストラを通じて多くのデータを渡すときにも発生する可能性があります。

アプリケーションでこの例外が発生した場合は、コードを分析してください。

  1. サービスとアプリケーションの間で大量のデータを交換していますか?
  2. インテントを使用して大量のデータを共有する(たとえば、ユーザーがギャラリー共有のプレスシェアから膨大な数のファイルを選択すると、選択したファイルのURIがインテントを使用して転送されます)
  3. サービスからビットマップファイルを受信する
  4. Androidが巨大なデータで応答するのを待つ(たとえば、ユーザーが多くのアプリケーションをインストールしたときのgetInstalledApplications())
  5. 保留中の操作が多い場合のapplyBatch()の使用

この例外が発生したときの処理方法

可能であれば、大きな操作を小さなチャンクに分割します。たとえば、applyBatch()を1000回の操作で呼び出すのではなく、100回ずつ呼び出します。

サービスとアプリケーション間で巨大なデータ(> 1MB)を交換しないでください

私はこれを行う方法を知りませんが、膨大なデータを返す可能性があるandroidをクエリしないでください:-)


1
私の.apkがインストールされているかどうかを確認していると思いますか?インストール時に... com.test.installedornotのパッケージを確認しているときに同じ例外が発生します。
DJhon

15
への呼び出し中にこの例外が発生しgetInstalledApplicationsます。これを解決するにはどうすればよいですか?
スタン

1
@StanこのAPIは一般的で、Androidアプリで広く使用されています。この例外を使用すると、このAPIを使用するときにどういうわけか本当に心配になります。
平和への情熱2014年

7
制限が500KB前後のどこかにあるというあなたの結論を確認できますが、それはデバイス固有であり、一部のデバイスでは、ほぼ1MB全体を転送できます。私もこの例外を抱えていたので、調査を行い、この問題を抱えている人々にとって興味深いかもしれない投稿を書きました。nemanjakovacevic.net/blog/english/2015/03/24/...
ネマニャKovacevic

11
クラッシュの原因となっている状態を正確に追跡するのが難しい場合は、TooLargeToolが便利です。
Max Spencer

48

クラッシュの原因となっているパーセルを調査する必要がある場合は、TooLargeToolを試すことを検討してください

(これは、受け入れられた回答の下で@Max Spencerからのコメントとして見つかりました。私の場合は役に立ちました。)


9
最も過小評価されているソリューション。このツールは、問題のあるアクティビティを絞り込むのに役立ちます
Kedar Paranjape

このツールは私の問題の解決に役立ちました。簡単にインストールして使用できます。
Carlos、

このツールはkotlin用です:/ javaの代わりはありますか?
maxwellnewage

2
@maxwellnewage:最新バージョン(0.2.1、0.2.0も)は現在、Javaのみのアプリケーションでは機能ないようです。私はバージョン0.1.6を使用する必要があり、それはそれでうまくいきました
ハイゼンベルク

このツールを使用して、フラグメントで巨大なサイズのバンドルを使用していたことを検出しました。私がしたことは、バンドルから引数を抽出し、使用してバンドルをクリアしましたbundle.clear()
EJ Chathuranga

41

これは決定的な答えではありませんが、aの原因TransactionTooLargeExceptionを解明し、問題を特定するのに役立ちます。

ほとんどの回答は転送された大量のデータに関するものですが、大量のスクロールとズーム、およびActionBarスピナーメニューを繰り返し開いた後に、この例外が偶発的にスローされるのがわかります。クラッシュは、アクションバーをタップすると発生します。(これはカスタムマッピングアプリです)

受け渡される唯一のデータは、「入力ディスパッチャー」からアプリへのタッチのようです。これは、「トランザクションバッファ」の1 mb近くには合理的に達しないと思います。

私のアプリはクアッドコア1.6 GHzデバイスで実行されており、3つのスレッドを使用して重量物を持ち上げ、UIスレッド用に1つのコアを解放しています。さらに、このアプリは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のソースコードを詳しく調べると、次の行が見つかります。

frameworks / base / core / jni / android_util_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);

私には、このドキュメントに記載されていない機能を使用している可能性があります。この場合、トランザクションがTooLargeである以外の理由でトランザクションが失敗します。彼らはそれに名前を付けるべきだったTransactionTooLargeOrAnotherReasonException

現時点では問題を解決していませんが、何か役に立つと思った場合は、この回答を更新します。

更新:コードが一部のファイル記述子をリークしたことが判明しました。その数はLinuxで最大化され(通常は1024)、これにより例外がトリガーされたようです。結局、それはリソースの問題でした。私はこれを/dev/zero1024回開いて確認しました。これにより、上記の例外や一部のSIGSEGVを含め、UI関連のアクションであらゆる種類の奇妙な例外が発生しました。どうやらファイル/ソケットを開くのに失敗したことは、Android全体で非常にきれいに処理/報告されるものではありません。


36

TransactionTooLargeException今、約4ヶ月間、私たちを苦しめてきた、と私たちは問題を最終的に解決してきました!

どのようなことは、我々が使用しているして起こっていたのFragmentStatePagerAdapterではViewPager。ユーザーはページをめくって100以上のフラグメントを作成します(その読み取りアプリケーション)。

でフラグメントを適切に管理していますがdestroyItem()、Androidの実装FragmentStatePagerAdapterにはバグがあり、次のリストへの参照が保持されています。

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サブクラスでフラグメントを適切に管理している場合でも、基本クラスには、Fragment.SavedStateこれまでに作成されたすべてのフラグメントのが格納されます。これTransactionTooLargeExceptionは、そのアレイがaにダンプされparcelableArray、OSが100以上のアイテムを望まない場合に発生します。

したがって、私たちにとっての修正は、saveState()メソッドをオーバーライドし、何も保存しないことでした"states"

@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;
}

私にとって最良の答え。どうもありがとうございました
Pavel

これのすべての可能性の中で、私にとってこれは唯一の選択肢のように見えました。このサイズになるのを可能にする状態で何が保存されますか?状態がひどく必要でそれを保存するコードがある場合、これが他の問題を引き起こさないのはなぜですか?ありがとう
ケニー

@Kennyと同じ質問
Mr. Rabbit

1
@Override public Parcelable saveState() { Bundle bundle = (Bundle) super.saveState(); if (bundle != null) { Parcelable[] states = bundle.getParcelableArray("states"); // Subset only last 3 states if (states != null) states = Arrays.copyOfRange(states, states.length > 3 ? states.length - 3 : 0, states.length - 1); bundle.putParcelableArray("states", states); } else bundle = new Bundle(); return bundle; }
Ramy Sabry、2018

最後の3つの状態のみを許可します。上記のコードを確認してください。
Ramy Sabry、2018

20

TransactionTooLargeExceptionが表示される理由の答えを求めてひどく失望した人は、インスタンス状態で保存する情報の量を確認してください。

compile / targetSdkVersion <= 23では、保存された状態のサイズが大きいという内部警告しかありませんが、クラッシュするものはありません。

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)

しかし、compile / targetSdkVersion> = 24では、この場合、実際のRuntimeExceptionがクラッシュします。

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) 

何をすべきか?

ローカルデータベースにデータを保存し、このデータを取得するために使用できるインスタンス状態のIDのみを保持します。


それをグローバルパラメーターとして保持し、後で使用することは可能ですか?
Jitendra ramoliya

@Jitendraramoliyaはい、できます。それがまさに私の言いたいことです。
Yazon2006、19年

13

この例外は通常、アプリがバックグラウンドに送信されているときにスローされます。

そこで、データフラグメントメソッドを使用してonSavedInstanceStaeライフサイクルを完全に回避することにしました。私のソリューションは、複雑なインスタンス状態を処理し、メモリをできるだけ早く解放します。

最初に、データを格納するための単純なFargmentを作成しました。

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() );
}

詳細:http : //www.devsbedevin.net/avoiding-transactiontoolargeexception-on-android-nougat-and-up/


1
アプリがバックグラウンドにあるときにアクティビティが破棄され、フォアグラウンドアクティビティを実行しようとするとどうなりますか?
マスターディザスタ

その場合、@ MasterDisasterはインスタンスフラグメントを保持するプロセスが停止したため、状態は保存されません。
Vaiden、2017年

権利なので、このケースは構成の変更でのみ機能します。
マスターディザスタ

OSがトリガーするたびに機能しますonSavedState()。これは多くの場合に発生します。構成変更は1つです。アプリの切り替えとバックグラウンドへの移動は別です。そして、もっとあります。
Vaiden、2017年

1
このソリューションは、さまざまなソースからのデータを保存するように拡張する必要があると思います。値とキーとのバンドルなどのタグでおそらくHashMapの...
CoolMind

11

この問題の具体的な原因は1つではありません。私にとっては、私のFragmentクラスでこれを行っていました:

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);

9

デバイスの機能やアプリに関係なく、トランザクションバッファーは1 MBに制限されることを理解することが重要です。このバッファーは、ユーザーが行うすべてのAPI呼び出しで使用され、アプリが現在実行しているすべてのトランザクション間で共有されます。

私はそれがまた、小包などのようないくつかの特定のオブジェクトを保持していると信じて(Parcel.obtain())、それは常にすべてを一致させることが重要ですので、obtain()recycle()

このエラーは、返されるデータが1 MB未満であっても(他のトランザクションがまだ実行中の場合)、API呼び出しが大量のデータを返すときに簡単に発生する可能性があります。

たとえば、PackageManager.getInstalledApplication()呼び出しはインストールされているすべてのアプリのリストを返します。特定のフラグを追加すると、多くの追加データを取得できます。これを行うと失敗する可能性があるため、余分なデータを取得せず、アプリごとに取得することをお勧めします。

ただし、呼び出しは引き続き失敗する可能性があるため、で囲みcatch、必要に応じて再試行できるようにすることが重要です。

私の知る限り、このような問題の回避策は、再試行して、できるだけ少ない情報を取得するようにすることです。


情報をありがとう、そのバッファはアプリケーション内のすべてのトランザクションで共有されます!
Artem Mostyaev 2014年

1
これが事実だった場合、なぜ私はAndroid 4.4の携帯電話のみを使用し、他にはないのですか?4.4のバグのほうが多く、なぜなのかわかりません。
JPM 2015

9

私もサムスンS3でこの例外を受けました。私は2つの根本的な原因を疑っています、

  1. ロードしてメモリを大量に消費するビットマップがある場合、ダウンサイジングを使用します
  2. drawable-_dpiフォルダーから欠落しているいくつかのドローアブルがあり、androidはドローアブルでそれらを探し、サイズを変更して、setContentViewが突然ジャンプして大量のメモリを使用するようにします。

DDMSを使用して、アプリを再生しながらヒープを確認します。これにより、問題を引き起こしているsetcontentviewがわかります。

問題2を取り除くために、すべてのフォルダにすべてのドローアブルをコピーしました。

問題は解決されました。


メモリ/ビットマップの例外は通常異なって見えます。私はすでにAndroid 2.x〜4.xでテストしているそれらの多くを見ており、例外は常に異なって見えます。しかし、誰もが知っていることですが、これはおそらく関連していますが、4.xバージョンに固有のものです。
Ixx

10
問題の原因についての手がかりが得られないため、情報に関してはこれはひどい例外です。
Ixx

数日が終わったと思いますが、どのような結果が得られましたか?
デニー

8

これをアクティビティに追加してください

@Override
protected void onSaveInstanceState(Bundle oldInstanceState) {
    super.onSaveInstanceState(oldInstanceState);
    oldInstanceState.clear();
}

それは私にとってもうまくいく


7
私は、それが最も有害なヒントだと思います。復元したいデータをクリアする必要があるのはなぜonCreate()ですか?
CoolMind 2018

2
このコードの意味は、インスタンスの状態を保存しないことになります...
Justin

4

したがって、私たちにとっては、AIDLインターフェースを介してリモートサービスに送信するオブジェクトのサイズが大きすぎました。トランザクションサイズは1MBを超えることはできません。リクエストは512KBの個別のチャンクに分割され、インターフェイスを介して一度に1つ送信されます。私が知っている残忍なソリューションですが、ちょっと-そのAndroid :(


4

onSaveInstanceState メソッドから古いInstanceStateをクリアすると、うまく機能します。私はビューページャーにFragmentStatePagerAdapterを使用しているので、InstanceStateを明確にするために、親アクティビティのOverrideメソッドを下に保ちます。

@Override
protected void onSaveInstanceState(Bundle InstanceState) {
             super.onSaveInstanceState(InstanceState);
             InstanceState.clear();
}

私はここからNougatのandroid.os.TransactionTooLargeExceptionからこの解決策を見つけました


どうもありがとうございます。
アンドレイン、

答えてくれてありがとう
ジャティン・パテル

3

最近、Androidの連絡先プロバイダーで作業しているときに、興味深いケースにも遭遇しました。

内部連絡先データベースから連絡先の写真を読み込む必要があり、システムアーキテクチャによれば、このすべてのデータはクエリによって連絡先プロバイダーに配信されます。

独立したアプリケーションとして機能するため、あらゆる種類のデータ転送がバインダーメカニズムを使用して実行されるため、ここでバインダーバッファーが使用されます。

私の主な間違いは、連絡先プロバイダーから取得したwith blobデータを閉じなかったCursorため、プロバイダーに割り当てられたメモリが増加!!!FAILED BINDER TRANSACTION!!!し、LogCat出力に大量のメッセージが表示されるまで、バインダーバッファーが膨らみました。

したがって、主な考え方は、外部のコンテンツプロバイダーと連携しCursorてそれらからs を取得した場合は、それらの連携が終了したら必ず閉じることです。


3

Intentを介してビットマップを送信しようとしたときに同じ問題に直面し、同時にそれが発生したときにアプリケーションを折りたたみました。

この記事で説明したリンクの説明をここ入力する方法アクティビティが停止処理中に発生します。つまり、アクティビティが保存された状態のバンドルをシステムOSに送信して、後で復元できるように安全に保管しようとしています(構成変更後)。または死を処理する)が、送信した1つ以上のバンドルが大きすぎた。

私のアクティビティでonSaveInstanceStateをオーバーライドすることにより、ハックを介してそれを解決しました:

@Override
protected void onSaveInstanceState(Bundle outState) {
    // super.onSaveInstanceState(outState);
}

コメントコールスーパー。汚いハックですが、完全に機能しています。ビットマップはクラッシュすることなく正常に送信されました。これが誰かを助けることを願っています。


2

私の場合、ネイティブライブラリがSIGSEGVでクラッシュした後、二次クラッシュとしてTransactionTooLargeExceptionが発生します。ネイティブライブラリのクラッシュは報告されないため、TransactionTooLargeExceptionのみを受け取ります。


2

大きなContentValues []をbulkInsertしようとしたときに、syncadapterでこれを取得しました。次のように修正することにしました。

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));
}

2
他の人が失敗した場合はどうなりますか?ループを使用して、さらに分割する必要があります。トランザクションサイズを取得して最大トランザクションサイズを取得する方法はありますか?
android開発者

2

私にとってもでしたがFragmentStatePagerAdapter、オーバーライドsaveState()は機能しませんでした。修正方法は次のとおりです。

FragmentStatePagerAdapterコンストラクターを呼び出すときは、クラス内にフラグメントの個別のリストを保持し、フラグメントを削除するメソッドを追加します。

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...
}

次にActivity、でViewPager位置を保存adapter.removeFragments()し、オーバーライドされたonSaveInstanceState()メソッドを呼び出します。

private int pagerPosition;

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //save other view state here
    pagerPosition = mViewPager.getCurrentItem();
    adapter.removeFragments();
}

最後に、オーバーライドされたonResume()メソッドで、そうでない場合はアダプターを再インスタンス化しますnull。(それはだ場合はnull、そのActivityアプリはアンドロイドではオフに殺された後にいる、初めて開かれたりしているonCreateアダプターの作成を行います。)

@Override
public void onResume() {
    super.onResume();
    if (adapter != null) {
        adapter = new PagerAdapter(frags);
        mViewPager.setAdapter(adapter);
        mViewPager.setCurrentItem(currentTabPosition);
    }
}

1

大きなサイズのIntentオブジェクトデータを入力しないようにしてください。私の場合、文字列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);

これは非常に悪い考えです。このように静的変数を使用すると、コードのにおいがします。また、「アクティビティを保持しない」フラグを指定してこのコードを実行し、PageWebViewに移動した後、Homeキーを押してみてください。アクティビティを再度開いた後、MainActivityがすべての変数で100%停止するため、おそらくクラッシュします。
Kyrylo Zapylaiev 2017

1

私がWebView自分のアプリでを扱っているとき、それは起こります。addViewUIリソースに関連していると思います。私のアプリでWebViewActivityは、以下のようにコードを追加しますが、正常に実行されます。

@Override
protected void onDestroy() {
    if (mWebView != null) {
        ((ViewGroup) mWebView.getParent()).removeView(mWebView);  
        mWebView.removeAllViews();  
        mWebView.destroy();
    }
    super.onDestroy();
}

1

私はこれの根本的な原因を見つけました(mvdsが言うように、「ウィンドウの追加に失敗しました」とファイル記述子のリークの両方が発生しました)。

あるバグがBitmapFactory.decodeFileDescriptor()アンドロイド4.4の。inPurgeableand inInputShareableBitmapOptionsに設定されている場合にのみ発生しtrueます。これは、ファイルと対話する多くの場所で多くの問題を引き起こします。

このメソッドはからも呼び出されることに注意してくださいMediaStore.Images.Thumbnails.getThumbnail()

Universal Image Loaderはこの問題の影響を受けます。ピカソグライドは影響を受けていないようです。 https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020


1

writeToParcel(Parcel dest、int flags)メソッドのこの1行のコードは、TransactionTooLargeExceptionを取り除くのに役立ちました。

dest=Parcel.obtain(); 

このコードの後、私はすべてのデータをパーセルオブジェクト、つまりdest.writeInt()などに書き込みます。


1

ソリューションを使用するEventBusなどしてみてくださいContentProvider

同じプロセス(通常はすべてのアクティビティがそうです)にいる場合はEventBus、を使用してみてください。プロセス内のデータ交換には多少のバッファーは必要ないため、データが大きすぎることを心配する必要はありません。(メソッド呼び出しを使用して実際にデータを渡すことができ、EventBusは醜いものを隠します)詳細は次のとおりです。

// one side
startActivity(intentNotTooLarge);
EventBus.getDefault().post(new FooEvent(theHugeData));

// the other side
@Subscribe public void handleData(FooEvent event) { /* get and handle data */ }

Intentの2つのサイドが同じプロセスにない場合は、少し試してくださいContentProvider


TransactionTooLargeExceptionを参照してください

バインダートランザクションが大きすぎるため、失敗しました。

リモートプロシージャコール中に、呼び出しの引数と戻り値は、バインダートランザクションバッファーに格納されたParcelオブジェクトとして転送されます。引数または戻り値が大きすぎてトランザクションバッファーに収まらない場合、呼び出しは失敗し、TransactionTooLargeExceptionがスローされます。


1

Android EspressoテストのStackoverflowエラーからTransactionTooLargeExceptionが発生しました。アプリのLogcatフィルターを外したときに、ログにstackoverflowエラースタックトレースが見つかりました。

Espressoが非常に大きな例外スタックトレースを処理しようとしたときにTransactionTooLargeExceptionを引き起こしたと思います。


1

次のものを使用できます。

android:largeHeap="true"

Androidマニフェストのapplicationタグの下。

これは私の場合の問題を解決しました!


私の場合(onSaveInstantStateアクティビティ/フラグメントを呼び出して大きなリストを保存するため)、それは役に立ちませんでした。
CoolMind

1
そもそも大量のデータが保存される理由に対処していないので、これは悪い習慣だと考えられています。新しいデバイスでは、アプリがクラッシュし、制限がはるかに小さくなります(256KB)。最初にロットを保管する理由を調査し、それを減らします。
Tim Kist

1

また、あるアクティビティから別のアクティビティに渡されるビットマップデータについてこの問題に直面していましたが、データを静的データとして解決策を作成しましたが、これは私にとって完璧に機能しています

最初に活動中:

public static Bitmap bitmap_image;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_first);
   bitmap_image=mybitmap;
}

そして2番目の活動では:

 @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
   Bitmap mybitmap=first.bitmap_image;
}

1

これは私のアプリで発生していました。フラグメントの引数で検索結果のリストを渡し、そのリストをフラグメントのプロパティに割り当てていたためです。これは、実際にはフラグメントの引数が指すメモリ内の同じ場所への参照です。リストの新しい項目。フラグメントの引数のサイズも変更されました。アクティビティが一時停止されると、基本フラグメントクラスはフラグメントの引数をonSaveInstanceStateに保存しようとします。これは、引数が1MBより大きい場合にクラッシュします。例えば:

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"));
    }
}

さらに良い解決策は、引数であまり多くのデータを渡さないことです。

この答えTooLargeToolの助けがなければ、私はおそらくこれを見つけられなかっただろう。


1

TransactionTooLargeExceptionも住んでいます。まず、それがどこで発生するかを理解することに取り組みました。それが起こる理由を知っています。コンテンツが多いので、誰もが知っています。私の問題はそのようなもので、私は解決しました。たぶん、この解決策は誰にとっても役立ちます。APIからコンテンツを取得するアプリがあります。最初の画面でAPIから結果を取得し、2番目の画面に送信します。このコンテンツを2番目の画面に正常に送信できます。2番目の画面の後に3番目の画面に移動したい場合、この例外が発生します。各画面はフラグメントから作成されています。セカンドスクリーンから離れると気づきました。バンドルコンテンツを保存します。このコンテンツが大きすぎる場合、この例外が発生します。私の解決策は、バンドルからコンテンツを取得した後、それをクリアすることです。

class SecondFragment : BaseFragment() {

    lateinit var myContent: MyContent

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        myContent = arguments?.getParcelable("mycontent")
        arguments?.clear()
    }

これは正しいです(私には恥ずかしいですが、1年後には同じことがわかりました)が、フラグメントを再作成(画面の回転)した場合、フラグメントはどのように機能しますか?
CoolMind

0

解決策は、アプリがArrayList(または問題を引き起こしているオブジェクト)をファイルシステムに書き込んでから、Intentを介してそのファイルへの参照(ファイル名/パスなど)をIntentServiceに渡し、IntentServiceに任せることです。ファイルの内容を取得して、ArrayListに変換します。

IntentServiceがファイルの処理を完了すると、ファイルを削除するか、ローカルブロードキャストを介して命令をアプリに返し、作成したファイルを削除します(ファイルに提供されたのと同じファイル参照を返します)。

詳細については、この関連する問題に対する私の回答を参照しください。


0

インテント、コンテンツプロバイダー、メッセンジャー、電話、バイブレーターなどのすべてのシステムサービスは、バインダーによるIPCイン​​フラストラクチャプロバイダーを利用します。さらに、アクティビティライフサイクルコールバックもこのインフラストラクチャを使用します。

1MBは、特定の瞬間にシステムで実行されるすべてのバインダートランザクションの全体的な制限です。

インテントの送信時に大量のトランザクションが発生している場合、余分なデータが大きくなくても失敗する可能性があります。http://codetheory.in/an-overview-of-android-binder-framework/


0

TransactionTooLargeExceptionが発生する可能性のある場所が非常に多いため、Android 8の新機能がもう1つあります。コンテンツが大きすぎる場合に、誰かが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が発生するようです。

いくつかのことが緩和される可能性があります(または、とにかくテストを行っていたように行いました):android:importantForAutofill="noExcludeDescendants"EditTextのxmlレイアウト宣言を追加します。またはコードで:

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);
}

2番目のひどい、ひどい回避策は、performClick()およびonWindowFocusChanged()メソッドをオーバーライドして、TextEditサブクラス自体でエラーをキャッチすることです。でもそれは賢いことだとは思いません...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.