IT story

TransactionTooLargeException에서 수행 할 작업

hot-time 2020. 4. 24. 08:09
반응형

TransactionTooLargeException에서 수행 할 작업


나는 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


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

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

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

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

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

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

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

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


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

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

전달되는 유일한 데이터는 "입력 디스패처"에서 앱으로 터치하는 것 같습니다. 나는 이것이 "트랜잭션 버퍼"에서 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);

나에게 그것은 문서화되지 않은 기능에 타격을 입힌 것처럼 들릴 수 있는데, 트랜잭션이 너무 큰 것이 아닌 다른 이유로 트랜잭션이 실패합니다. 그들은 그것을 이름을 붙여야 TransactionTooLargeOrAnotherReasonException했다

현재로서는 문제를 해결하지 못했지만 유용한 정보가 있으면이 답변을 업데이트하겠습니다.

업데이트 : 내 코드에서 일부 파일 설명자가 유출되었으며, 그 수는 Linux에서 최대화되어 (일반적으로 1024) 예외가 발생했습니다. 결국 자원 문제였습니다. /dev/zero1024 번 열어서 이것을 확인 하여 위의 예외 및 일부 SIGSEGV를 포함하여 UI 관련 작업에서 모든 종류의 이상한 예외가 발생했습니다. 분명히 파일 / 소켓을 열지 못하는 것은 Android 전체에서 매우 깨끗하게 처리 /보고되는 것이 아닙니다.


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

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

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


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 만 유지하십시오.


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

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

그래서 나는 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/


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

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

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

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

문제가 해결되었습니다.


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

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

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

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

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

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


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

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

그것은 나를 위해 일하고 또한 그것은 당신을 도울 것입니다 희망


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


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

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

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

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

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


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


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

나를 위해 그것은 또한 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);
    }
}

큰 크기의 인 텐트 오브젝트 데이터를 넣지 마십시오. 필자의 경우 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);

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

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

나는 이것의 근본 원인을 발견했다 (우리는 "창 추가 실패"와 mvds가 말한 것처럼 파일 디스크립터 누출을 얻었다).

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

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

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


writeToParcel (Parcel dest, int flags) 메소드의이 한 줄의 코드는 TransactionTooLargeException을 제거하는 데 도움이되었습니다.

dest=Parcel.obtain(); 

이 코드 만 후에는 모든 데이터를 소포 객체, 즉 dest.writeInt () 등에 쓰고 있습니다.


솔루션 을 사용 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이 발생합니다.


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

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

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

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

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


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

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


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

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

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


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

android:largeHeap="true"

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

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


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

활동 우선 :

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

검색 결과 목록을 조각 인수로 전달하고 해당 목록을 조각 속성에 할당하기 때문에 실제로 앱에서 발생했습니다.이 조각은 실제로 조각의 인수가 가리키는 메모리의 동일한 위치에 대한 참조입니다. 목록에 새 항목을 추가하여 조각의 인수 크기를 변경했습니다. 활동이 일시 중단되면 기본 조각 클래스는 조각의 인수를 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 의 도움 없이는 이것을 찾지 못했을 것 입니다.


해결책은 응용 프로그램이 파일 시스템에 ArrayList (또는 문제를 일으키는 모든 객체)를 파일 시스템에 작성한 다음 Intent를 통해 해당 파일에 대한 참조 (예 : 파일 이름 / 경로)를 IntentService에 전달한 다음 IntentService에 보내는 것입니다. 파일 내용을 검색하여 다시 ArrayList로 변환하십시오.

IntentService가 파일을 다 사용한 경우 파일을 삭제하거나 로컬 브로드 캐스트를 통해 앱으로 명령을 다시 전달하여 작성된 파일을 삭제해야합니다 (제공된 동일한 파일 참조를 다시 전달).

자세한 내용은 이 관련 문제에 대한 답변을 참조하십시오 .


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

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

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


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 하위 클래스 자체에서 오류를 포착하는 것입니다. 그러나 나는 그것이 현명하다고 생각하지 않습니다 ...


나를 위해 TransactionTooLargeException의도를 통해 한 활동에서 다른 활동으로 큰 비트 맵 이미지 를 보내려고 할 때 발생했습니다 . 응용 프로그램의 전역 변수를 사용 하여이 문제를 해결했습니다 .

예를 들어, 활동 A 에서 활동 B 로 큰 비트 맵 이미지를 보내려면 해당 비트 맵 이미지를 전역 변수에 저장하십시오.

((Global) this.getApplication()).setBitmap(bitmap);

그런 다음 활동 B를 시작하고 전역 변수에서 읽습니다.

Bitmap bitmap = ((Global) this.getApplication()).getBitmap();

참고 URL : https://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception

반응형