Подтвердить что ты не робот

Фрагмент в ViewPager не восстановлен после popBackStack

Проблема

Фрагмент не привязан к его хостингу ViewPager после возвращения из другого фрагмента.

Ситуация

Один объект, в котором размещен фрагмент, чей макет содержит ViewPager (PageListFragment в приведенном ниже примере). ViewPager заполнен FragmentStateViewPagerAdapter. Отдельные фрагменты, размещенные внутри пейджера (PageFragment в приведенном ниже примере), могут открывать списки вспомогательных страниц, содержащие новый набор страниц.

Поведение

Все работает нормально, пока кнопка "Назад" не нажата. Как только пользователь закрывает один из субстраний, предыдущий список воссоздается, но без страницы, которая была показана ранее. Пролистание других страниц в родительском PageList все еще работает.

код

Пример приложения можно найти на github:

Activity

public class MainActivity extends FragmentActivity {

private static final String CURRENT_FRAGMENT = MainActivity.class.getCanonicalName() + ".CURRENT_FRAGMENT";

public static final String ARG_PARENTS = "Parents";

public void goInto(String mHostingLevel, String mPosition) {
    Fragment hostingFragment = newHostingFragment(mHostingLevel, mPosition);
    addFragment(hostingFragment);
}

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

private void addBaseFragment() {
    Fragment hostingFragment = newHostingFragment("", "");
    addFragment(hostingFragment);
}

private Fragment newHostingFragment(String mHostingLevel, String oldPosition) {
    Fragment hostingFragment = new PageListFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARENTS, mHostingLevel + oldPosition +" > ");
    hostingFragment.setArguments(args);
    return hostingFragment;
}

private void addFragment(Fragment hostingFragment) {
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.fragmentSpace, hostingFragment, CURRENT_FRAGMENT);
    transaction.addToBackStack(null);
    transaction.commit();
}

}

PageListFragment

public class PageListFragment extends Fragment {

private String mParentString;

public PageListFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_hosting, container, false);
}

@Override
public void onResume() {
    mParentString = getArguments().getString(MainActivity.ARG_PARENTS);
    ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewPager);
    viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
    super.onResume();
}

private static class SimpleFragmentStatePagerAdapter extends FragmentStatePagerAdapter {

    private String mHostingLevel;

    public SimpleFragmentStatePagerAdapter(FragmentManager fm, String hostingLevel) {
        super(fm);
        this.mHostingLevel = hostingLevel;
    }

    @Override
    public android.support.v4.app.Fragment getItem(int position) {
        PageFragment pageFragment = new PageFragment();
        Bundle args = new Bundle();
        args.putString(MainActivity.ARG_PARENTS, mHostingLevel);
        args.putInt(PageFragment.ARG_POSITION, position);
        pageFragment.setArguments(args);
        return pageFragment;
    }

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

PageFragment

public class PageFragment extends Fragment {

public static final String ARG_POSITION = "Position";

private String mHostingLevel;
private int mPosition;

public PageFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View contentView = inflater.inflate(R.layout.fragment_page, container, false);
    setupTextView(contentView);
    setupButton(contentView);
    return contentView;
}

private void setupTextView(View contentView) {
    mPosition = getArguments().getInt(ARG_POSITION);
    mHostingLevel = getArguments().getString(MainActivity.ARG_PARENTS);
    TextView text = (TextView) contentView.findViewById(R.id.textView);
    text.setText("Parent Fragments " + mHostingLevel + " \n\nCurrent Fragment "+ mPosition);
}

private void setupButton(View contentView) {
    Button button = (Button) contentView.findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            openNewLevel();
        }
    });
}

protected void openNewLevel() {
    MainActivity activity = (MainActivity) getActivity();
    activity.goInto(mHostingLevel, Integer.toString(mPosition));
}

}
4b9b3361

Ответ 1

После продолжительного расследования это оказывается проблемой с менеджером фрагментов.

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

java.lang.IllegalStateException: Recursive entry to executePendingTransactions 

при попытке изменить фрагменты внутри FragmentPager.

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

Вместо

    viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));

делать

    viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getChildFragmentManager(),mParentString));

Смотрите также: github

Ответ 2

Что Павел не упомянул, если вы используете getChildFragmentManager, тогда вы будете страдать от проблемы "пустой экран по назад".