TransactionTooLargeException에서 수행 할 작업


239

나는 TransactionTooLargeException. 재현 할 수 없습니다. 문서에서 그것은 말합니다

바인더 트랜잭션이 너무 커서 실패했습니다.

원격 프로 시저 호출 동안, 인수 및 호출의 리턴 값은 바인더 트랜잭션 버퍼에 저장된 Parcel 오브젝트로 전송됩니다. 인수 또는 반환 값이 너무 커서 트랜잭션 버퍼에 맞지 않으면 호출이 실패하고 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)

조회수와 관련이있는 것 같습니다. 이것은 원격 프로 시저 호출과 어떤 관련이 있습니까?

어쩌면 중요한 : 안드로이드 버전 : 4.0.3, 기기 : HTC One X


아니요.하지만 다시받지 못했습니다. 라이브 앱에 오류 추적기가 있고 약 3 주 동안이 오류를 한 번만 얻었습니다. 최소한 자주 발생하지 않는 것 같습니다. 어쩌면 안드로이드에서 문제를
열만

답변이 없지만 Galaxy S2가 안정적으로 재설정됩니다.
Timmmm

나는 오늘 내 응용 프로그램 중 하나에서 이런 일이 발생했습니다. 이것은 갤럭시 S3에서도 한 번만 발생했습니다. 이것은 더 강력한 장치로만 이해되는 것 같습니다.
danwms

이 예외는 API 15, developer.android.com/reference/android/os/ 에 추가되었습니다. 그리고지도를 스크롤하면서 MapView에서이를 재현했습니다. gc가 남은 기억이 없다고 썼을 때까지 (몇 분이 걸렸습니다)
meh

트랜잭션 버퍼는 모든 장치에서 1MB로 제한되며이 버퍼는 모든 트랜잭션을 유지합니다. 따라서 장치가 강력할수록 더 많은 트랜잭션을 동시에 수행 할 수 있으며 모두 동일한 1MB 버퍼를 사용합니다. 즉, 귀하의 답변은 답변이 아니라 의견입니다.
3c71

답변:


158

이 문제가 발생하여 서비스와 응용 프로그램간에 엄청난 양의 데이터가 교환되는 경우 많은 썸네일을 전송합니다. 실제로 데이터 크기는 약 500kb이고 IPC 트랜잭션 버퍼 크기는 1024KB로 설정되어 있습니다. 왜 트랜잭션 버퍼를 초과했는지 잘 모르겠습니다.

인 텐트 엑스트라를 통해 많은 양의 데이터를 전달할 때도 발생할 수 있습니다.

응용 프로그램에서이 예외가 발생하면 코드를 분석하십시오.

  1. 서비스와 응용 프로그램간에 많은 데이터를 교환하고 있습니까?
  2. 인 텐트를 사용하여 대용량 데이터 공유 (예 : 사용자가 갤러리 공유 프레스 공유에서 많은 수의 파일을 선택하면 선택한 파일의 URI가 인 텐트를 사용하여 전송 됨)
  3. 서비스에서 비트 맵 파일 받기
  4. 사용자가 많은 응용 프로그램을 설치할 때 getInstalledApplications ()와 같이 Android가 큰 데이터로 응답을 기다리는 경우
  5. 많은 작업이 보류중인 applyBatch () 사용

이 예외가 발생했을 때 처리하는 방법

가능한 경우 큰 작업을 작은 청크로 분할합니다 (예 : 1000 개의 작업으로 applyBatch ()를 호출하는 대신 100 개씩 호출).

서비스와 응용 프로그램간에 거대한 데이터 (> 1MB)를 교환하지 마십시오

나는 이것을하는 방법을 모른다. 그러나 거대한 데이터를 반환 할 수있는 안드로이드를 쿼리하지 마라 :-)


1
내 .apk가 설치되어 있는지 확인하고 있습니까? 설치시 ... com.test.installedornot. 내 패키지를 확인하는 동안 동일한 예외가 발생합니다. 내 .apk 크기가 9MB 이상이면이 예외를 어떻게 관리합니까?
DJhon

15
에 전화하는 동안이 예외가 발생합니다 getInstalledApplications. 이 문제를 해결하기 위해 무엇을 할 수 있습니까?
Stan

1
@Stan이 API는 일반적이며 Android 앱에서 널리 사용됩니다. 이 예외는이 API를 사용할 때 어떻게 든 걱정됩니다.
peacepassion

7
500KB 정도의 한계에 대한 결론을 확인할 수 있지만 장치마다 다르며 일부 장치에서는 거의 전체 1MB를 전송할 수 있습니다. 나는 또한이 예외가 있었기 때문에 조사를 하고이 문제가있는 사람들에게 흥미로운 읽을 수있는 게시물을 썼습니다. nemanjakovacevic.net/blog/english/2015/03/24/…
Nemanja Kovacevic 1

11
충돌을 일으키는 정확한 상태를 추적하기 어려운 경우 TooLargeTool이 유용 할 수 있습니다 .
Max Spencer

48

충돌을 일으키는 Parcel을 조사해야하는 경우 TooLargeTool 시도를 고려해야 합니다.

(이 답변을 @Max Spencer의 의견으로 받아 들였으며 제 경우 도움이되었습니다.)


9
가장 과소 평가 된 솔루션. 이 도구를 사용하면 공격 활동을 좁힐 수 있습니다.
Kedar Paranjape

이 도구는 내 문제를 해결하는 데 도움이되었습니다. 설치 및 사용이 쉽습니다.
Carlos

이 도구는 kotlin을위한 것입니다.
maxwellnewage 2016 년

2
@ maxwellnewage : 최신 버전 (0.2.1, 0.2.0도)이 현재 Java 전용 응용 프로그램에서 작동하지 않는 것 같습니다 . 0.1.6 버전을 사용해야했고 잘 작동했습니다
heisenberg

이 도구를 사용하여 조각에 거대한 크기의 번들을 사용하고 있음을 감지했습니다. 내가 한 것은 번들에서 인수를 추출하고 다음을 사용하여 번들을 지우는 것입니다.bundle.clear()
EJ Chathuranga

41

이것은 명확한 대답은 아니지만 TransactionTooLargeException문제 의 원인을 밝히고 문제를 정확히 찾아내는 데 도움이 될 수 있습니다.

대부분의 답변은 전송 된 많은 양의 데이터를 언급하지만 ActionBar 스피너 메뉴를 많이 스크롤하고 확대 / 축소하고 반복적으로 열면이 예외가 우연히 발생합니다. 작업 표시 줄을 탭하면 충돌이 발생합니다. (이것은 커스텀 매핑 앱입니다)

전달되는 유일한 데이터는 "입력 디스패처"에서 앱으로 터치하는 것 같습니다. 나는 이것이 "Transaction Buffer"에서 1MB 근처에 합리적으로 있다고 생각하지 않습니다.

내 응용 프로그램은 쿼드 코어 1.6GHz 장치에서 실행 중이며 무거운 스레드를 처리하기 위해 3 개의 스레드를 사용하므로 하나의 코어를 UI 스레드에 사용할 수 없습니다. 또한 응용 프로그램은 android : largeHeap을 사용하고 사용되지 않는 힙이 10MB 남고 힙을 늘리기 위해 100MB의 여유 공간이 있습니다. 그래서 나는 그것이 자원 문제라고 말하지 않을 것입니다.

충돌은 항상 다음 줄 바로 앞에옵니다.

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

안드로이드의 소스 코드를 살펴보면 다음 줄을 찾습니다.

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

그리고 안드로이드가 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해당 어레이가 덤프 될 때 발생할 수있는 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

@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

나는 단지 마지막 3 가지 상태 만 보도록 위 코드를 확인하십시오.
Ramy Sabry

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

13

이 예외는 일반적으로 앱이 백그라운드로 전송 될 때 발생합니다.

그래서 나는 onSavedInstanceStae라이프 사이클 을 완전히 피하기 위해 data Fragment 방법을 사용하기로 결정했습니다 . 내 솔루션은 복잡한 인스턴스 상태를 처리하고 최대한 빨리 메모리를 해제합니다.

먼저 데이터를 저장할 간단한 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

권리, 따라서이 경우는 구성 변경에서만 작동합니다.
마스터 재해

OS가 트리거 될 때마다 작동 onSavedState()하며 많은 경우에 발생합니다. 구성 변경은 하나입니다. 앱을 전환하고 백그라운드로 이동하는 것도 또 다른 방법입니다. 그리고 더 있습니다.
Vaiden

1
다른 소스의 데이터를 저장하려면이 솔루션을 확장해야한다고 생각합니다. 아마도 키로 태그와 값으로 번들을 가진 HashMap 일 것입니다.
CoolMind

11

이 문제의 구체적인 원인은 하나도 없습니다. 저에게 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

장치 기능이나 앱에 관계없이 트랜잭션 버퍼는 1MB로 제한됩니다. 이 버퍼는 모든 API 호출에 사용되며 앱이 현재 실행중인 모든 트랜잭션에서 공유됩니다.

필자는 소포와 같은 특정 객체도 보유하고 있다고 생각 (Parcel.obtain())하므로 항상 모든 obtain()것과 일치하는 것이 중요 합니다 recycle().

이 오류는 리턴 된 데이터가 1MB 미만 (다른 트랜잭션이 여전히 실행중인 경우) 인 경우에도 많은 데이터를 리턴하는 API 호출에서 쉽게 발생할 수 있습니다.

예를 들어, PackageManager.getInstalledApplication()호출은 설치된 모든 앱 목록을 반환합니다. 특정 플래그를 추가하면 많은 추가 데이터를 검색 할 수 있습니다. 그렇게하면 실패 할 수 있으므로 추가 데이터를 검색하지 않고 앱별로 검색하지 않는 것이 좋습니다.

그러나 통화가 계속 실패 할 수 있으므로 통화를 둘러싸고 catch필요한 경우 다시 시도 할 수 있어야합니다.

내가 아는 한, 다시 시도하고 가능한 한 적은 정보를 검색하는 것을 제외하고는 이러한 문제에 대한 해결 방법이 없습니다.


응용 프로그램 내 모든 트랜잭션간에 버퍼가 공유된다는 정보에 감사드립니다!
Artem Mostyaev

1
이것이 사실이라면 왜 Android 4.4 전화 만 받고 다른 곳은 없습니다. 나는 4.4에서 그 이유를 알 수없는 버그가 더 많다고 생각합니다.
JPM

9

삼성 S3 에서도이 예외가 발생했습니다. 2 가지 근본 원인이 의심됩니다.

  1. 로드 및 너무 많은 메모리를 차지하는 비트 맵이 있습니다.
  2. drawable-_dpi 폴더에서 누락 된 드로어 블이 있고 안드로이드는 드로어 블에서 찾은 다음 크기를 조정하여 setContentView가 갑자기 점프하여 많은 메모리를 사용합니다.

DDMS를 사용하고 앱을 재생할 때 힙을 확인하면 문제를 일으키는 setcontentview에 대한 정보가 표시됩니다.

문제 2를 제거하기 위해 모든 폴더에서 모든 드로어 블을 복사했습니다.

문제가 해결되었습니다.


메모리 / 비트 맵 예외는 보통 다르게 보입니다. 나는 이미 안드로이드 2.x-4.x로 테스트하는 것을 보았고 예외는 항상 다르게 보입니다. 그러나이 사실은 아마도 관련이 있지만 4.x 버전과 관련이있을 수 있습니다.
Ixx

10
문제가 어디에서 왔는지에 대한 단서가 없기 때문에 정보와 관련하여 끔찍한 예외입니다.
Ixx

며칠이 지난 것 같아요, 당신의 발견은 무엇입니까?
데니

8

이것을 활동에 추가하십시오

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

그것은 또한 당신을 도울 것입니다 희망을 위해 작동


7
나는 그것이 가장 해로운 힌트라고 생각합니다. 복원하려는 데이터를 지우는 이유는 무엇 onCreate()입니까?
CoolMind

2
이 코드의 의미는 인스턴스 상태를 저장하지 않는다는 것입니다.
Justin

4

우리에게는 AIDL 인터페이스를 통해 너무 큰 객체를 원격 서비스로 보내려고했습니다. 트랜잭션 크기는 1MB를 초과 할 수 없습니다. 요청은 512KB의 개별 청크로 나뉘어 인터페이스를 통해 한 번에 하나씩 전송됩니다. 내가 아는 야만적 인 해결책-안드로이드 :(


4

onSaveInstanceState 메소드 에서 이전 InstanceState를 지우면 제대로 작동합니다. 내 viewpager에 FragmentStatePagerAdapter 를 사용하고 있으므로 명확한 InstanceState를 위해 재정의 메서드를 부모 활동에 유지합니다.

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

Nougat의 android.os.TransactionTooLargeException 에서이 솔루션을 찾았습니다 .


정말 고맙습니다.
Andrain

귀하의 답변이 저를 도와 주셔서 감사합니다
Jatin Patel

3

최근에는 Android의 연락처 제공자 와 작업하는 동안 흥미로운 사례가 발생했습니다 .

내부 연락처 데이터베이스에서 연락처 사진을로드해야했고 시스템 아키텍처에 따라이 모든 데이터는 쿼리를 통해 연락처 공급자에게 전달되었습니다.

별도의 응용 프로그램으로 작동하므로 모든 종류의 데이터 전송이 바인더 메커니즘을 사용하여 수행되므로 바인더 버퍼가 여기에서 작동합니다.

내 주요 실수이었다 내가 가까이하지 않았다Cursor 공급자에 할당 된 메모리가 증가하고 이것이 내가 톤 가지고 때까지 바인더 버퍼 팽창 그래서, 연락처 제공자로부터받은 BLOB 데이터와를 !!!FAILED BINDER TRANSACTION!!!내 로그 캣 출력에 메시지를.

따라서 주된 아이디어는 외부 컨텐츠 제공자와 작업 할 때 외부 컨텐츠 제공자와 Cursor작업 할 때 항상 컨텐츠 제공자와 작업을 마치면 닫으라는 것입니다.


3

Intent를 통해 비트 맵을 보내려고 할 때와 같은 문제에 직면했으며 동시에 응용 프로그램을 접었습니다.

이 기사에서 링크 설명을 입력 하면 액티비티가 중지 프로세스 중일 때 발생합니다. 즉, 액티비티가 나중에 복원을 위해 안전하게 유지하기 위해 저장된 상태 번들을 시스템 OS에 보내려고 시도했음을 의미합니다 (구성 변경 후) 또는 사망 처리)) 전송 한 번들 중 하나 이상이 너무 큽니다.

내 활동에서 onSaveInstanceState를 재정 의하여 해킹을 통해 해결했습니다.

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

댓글을 달고 슈퍼를 부르세요. 그것은 더러운 핵이지만 완벽하게 작동합니다. 충돌없이 비트 맵이 성공적으로 전송되었습니다. 이것이 누군가를 도울 수 있기를 바랍니다.


2

필자의 경우 네이티브 라이브러리가 SIGSEGV와 충돌 한 후 TransactionTooLargeException을 보조 충돌로 얻습니다. 원시 라이브러리 충돌은보고되지 않으므로 TransactionTooLargeException 만 수신합니다.


2

큰 ContentValues ​​[]를 bulkInsert하려고 할 때 내 동기화 어댑터에서 이것을 얻었습니다. 다음과 같이 수정하기로 결정했습니다.

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
다른 쪽이 실패하면 어떻게됩니까? 루프를 사용하여 더 많은 분할을 수행해야합니다. 트랜잭션 크기를 얻고 최대 트랜잭션 크기를 얻는 방법이 있습니까?
안드로이드 개발자

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

큰 크기의 인 텐트 오브젝트 데이터를 넣지 마십시오. 필자의 경우 String 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로 이동 한 후 홈을 누르십시오. 활동을 다시 연 후에는 MainActivity가 모든 변수와 함께 100 % 죽었으므로 충돌이 발생했을 수 있습니다.
Kyrylo Zapylaiev

1

WebView내 응용 프로그램에서 처리 할 때 발생합니다. addViewUI 리소스와 관련이 있다고 생각합니다 . 내 응용 프로그램에서 WebViewActivity아래 에 이와 같은 코드를 추가 하면 정상적으로 실행됩니다.

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

1

나는 이것의 근본 원인을 발견했다.

버그BitmapFactory.decodeFileDescriptor()안드로이드 4.4은. 이 경우에만 발생 inPurgeableinInputShareableBitmapOptions설정됩니다 true. 이것은 많은 장소에서 많은 문제를 일으켜 파일과 상호 작용합니다.

이 메소드도에서 호출됩니다 MediaStore.Images.Thumbnails.getThumbnail().

Universal Image Loader 는이 문제의 영향을받습니다. 피카소글라이드 는 영향을받지 않는 것 같습니다. https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020


1

writeToParcel (Parcel dest, int flags) 메소드의이 한 줄의 코드는 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의 양면이 동일한 프로세스가 아닌 경우 다소 시도하십시오 ContentProvider.


TransactionTooLargeException 참조

바인더 트랜잭션이 너무 커서 실패했습니다.

원격 프로 시저 호출 동안, 인수 및 호출의 리턴 값은 바인더 트랜잭션 버퍼에 저장된 Parcel 오브젝트로 전송됩니다. 인수 또는 반환 값이 너무 커서 트랜잭션 버퍼에 맞지 않으면 호출이 실패하고 TransactionTooLargeException이 발생합니다.


1

Android Espresso 테스트의 Stackoverflow 오류에서 TransactionTooLargeException이 발생했습니다. 내 앱의 Logcat 필터를 제거했을 때 로그에서 stackoverflow 오류 스택 추적을 발견했습니다.

Espresso가 실제로 큰 예외 스택 추적을 처리하려고 할 때 TransactionTooLargeException이 발생했다고 생각합니다.


1

하나를 사용할 수 있습니다 :

android:largeHeap="true"

Android Manifest에서 응용 프로그램 태그 아래에 있습니다.

이것은 내 경우의 문제를 해결했습니다!


제 경우에는 ( onSaveInstantState활동 / 조각 을 호출 하고 큰 목록을 저장 하기 때문에 ) 도움이되지 않았습니다.
CoolMind

1
처음에 많은 데이터가 저장되는 이유를 다루지 않기 때문에 이것은 나쁜 습관으로 간주됩니다. 최신 장치에서는 앱이 충돌하고 제한이 훨씬 작습니다 (256KB). 로트를 먼저 저장하는 이유를 조사하고 줄이십시오.
팀 키스트

1

또한 한 활동에서 다른 활동으로 전달되는 비트 맵 데이터에 대해이 문제에 직면했지만 내 데이터를 정적 데이터로 만들어 솔루션을 작성하면 완벽하게 작동합니다.

활동 우선 :

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

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의 결과를 얻고 두 번째 화면으로 보냅니다. 이 컨텐츠를 성공적으로 두 번째 화면으로 보낼 수 있습니다. 두 번째 화면 후 세 번째 화면으로 가고 싶다면이 예외가 발생합니다. 각 화면은 Fragment에서 생성됩니다. 두 번째 화면에서 나갔을 때 번들 컨텐츠를 저장합니다. 이 내용이 너무 크면이 예외가 발생합니다. 내 솔루션은 번들에서 콘텐츠를 얻은 후에 지 웁니다.

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

Intents, Content Providers, Messenger, Telephone, Vibrator 등과 같은 모든 시스템 서비스는 Binder의 IPC 인프라 제공자를 사용하며 활동 라이프 사이클 콜백도이 인프라를 사용합니다.

1MB는 특정 순간에 시스템에서 실행되는 모든 바인더 트랜잭션에 대한 전체 제한입니다.

의도가 전송 될 때 발생하는 많은 트랜잭션이있는 경우 추가 데이터가 크지 않더라도 실패 할 수 있습니다. http://codetheory.in/an-overview-of-android-binder-framework/


0

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이 발생하는 것 같습니다.

몇 가지가 그것을 완화시킬 수 있습니다 (또는 어쨌든 테스트 할 때) : 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);
}

두 번째 끔찍한 끔찍한 해결 방법은 performClick()onWindowFocusChanged()메소드를 재정 의하여 TextEdit 하위 클래스 자체에서 오류를 포착하는 것입니다. 그러나 나는 그것이 현명하다고 생각하지 않습니다 ...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.