TransactionTooLargeException при использовании FragmentStatePagerAdapter и запуске новой активности

На самом деле это проблема, возникшая откуда-то еще, но я сузил ее до следующего сценария. В моей MainActivity я использую ViewPager, чтобы иметь три вкладки внизу для переключения между моими тремя фрагментами. Если я нажимаю кнопку, чтобы перейти к новому действию после перехода к любому фрагменту, я получаю следующую ошибку:

FATAL EXCEPTION: main
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 861520 bytes
  at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3752)
  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:6077)
  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 861520 bytes
  at android.os.BinderProxy.transactNative(Native Method)
  at android.os.BinderProxy.transact(Binder.java:615)
  at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3606)
  at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3744)
  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:6077) 
  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) 

Однако, если я нажму кнопку перед перемещением между различными фрагментами в ViewPager, у меня не произойдет сбой. Я изучил все возможности сделать свои фрагменты просто полностью пустыми, чтобы увидеть, кроется ли проблема в этом, но, похоже, она связана с MainActivity или FragmentStatePagerAdapater.

Вот код для них обоих:

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import com.mypackage.Fragments.GroupsFragment;
import com.mypackage.Fragments.HomeFragment;
import com.mypackage.Fragments.ProfileFragment;
import com.mypackage.R;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Get the ViewPager and set it's PagerAdapter so that it can display items
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        viewPager.setAdapter(new MainFragmentPagerAdapter(getSupportFragmentManager()));

        // Give the TabLayout the ViewPager
        TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
        tabLayout.setupWithViewPager(viewPager);

        Button mTestButton = (Button) findViewById(R.id.test);

        mTestButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                moveToGroupActivity();
            }
        });
    }

    public void moveToGroupActivity() {
        Intent myIntent = new Intent(this, GroupActivity.class);
        startActivity(myIntent);
    }

    public static class MainFragmentPagerAdapter extends FragmentStatePagerAdapter {

        final int PAGE_COUNT = 3;
        private String tabTitles[] = new String[] { "Home", "Groups", "Profile" };

        public MainFragmentPagerAdapter(FragmentManager fm) {
            super(fm);


 }

    @Override
    public int getCount() {
        return PAGE_COUNT;
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return HomeFragment.newInstance();
            case 1:
                return GroupsFragment.newInstance();
            case 2:
                return ProfileFragment.newInstance();
            default:
                return null;
        }
    }

    @Override
    public CharSequence getPageTitle(int position) {
        // Generate title based on item position
        return tabTitles[position];
    }
}

}

Чтобы было ясно: у меня есть кнопка, которая переходит к другому действию в действии, состоящем из ViewPager, который перемещается между тремя фрагментами. Если я нажму кнопку перед тем, как перейти к другому фрагменту, он загрузится нормально. Если я перейду к фрагменту, а затем нажму кнопку, я получу указанный выше сбой.

Я никогда не использую onSaveInstanceState() или что-то в этом роде. Мое единственное предположение состоит в том, что FragmentStatePagerAdapter помещает фрагменты в память и вызывает сбой, но я действительно не знаю.


person scott13    schedule 04.01.2017    source источник
comment
Эта проблема возникает, когда вы передаете много данных между фрагментом или действием.   -  person Vishnu Magar    schedule 23.11.2019


Ответы (2)


Исключение TransactionTooLargeException мучает нас уже около 4 месяцев, и мы, наконец, решили эту проблему!

Происходило то, что мы использовали FragmentStatePagerAdapter в ViewPager. Пользователь будет пролистывать и создавать более 100 фрагментов (это приложение для чтения).

Хотя мы правильно управляем фрагментами в destroyItem(), в реализации FragmentStatePagerAdapter для Android есть ошибка, из-за которой сохраняется ссылка на следующий список:

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 возникает, когда этот массив сбрасывается в посылка, а ОС не нравится более 100 элементов.

Поэтому исправление для нас состояло в том, чтобы переопределить метод saveState() и ничего не сохранять для «состояний».

@Override
public Parcelable saveState() {
    Bundle bundle = (Bundle) super.saveState();
   bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
    return bundle;
}
person Mark    schedule 23.08.2018
comment
Скопировано из этого ответа: stackoverflow.com/a/43193467/3095845 - person Chris Chute; 27.07.2020

Эту проблему можно решить, очистив последний сохраненный экземпляр объекта. Попробуйте использовать в своем классе деятельности.

 @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.clear();
    }
person Sushil Chaudhary    schedule 12.03.2020