Отображение и скрытие фрагментов не фиксируются (не происходят) сразу при обновлении SwipeRefreshLayout

Так что в основном то, над чем я работаю, очень похоже на приложение Instagram, где есть несколько вкладок, и пользователи могут переключаться на любую вкладку без каких-либо задержек, независимо от того, что происходит, например, обновление, перезагрузка и т. д. Он также использует кнопку «Назад», чтобы вернуться к предыдущей сохраненной вкладке.

Для этого я использовал FragmentManager с FragmentTransaction для отображения и скрытия каждого фрагмента, представляющего каждую вкладку. Я не использовал replace или attach / detach, потому что они разрушают иерархию представлений предыдущей вкладки.

Моя реализация работает довольно хорошо, за исключением того, что показ и скрытие фрагментов не фиксируются (я очень сомневаюсь, что это правильное слово, но пока я так понял поток.) ​​или не происходят немедленно, когда SwipeRefreshLayout обновление фрагмента (который должен быть скрыт), который был добавлен в FragmentManager позже, чем отображаемый.

Моя реализация следует правилам, подобным этим. Допустим, у нас есть 4 вкладки, и моя MainActivity показывает первую вкладку, скажем, FirstFragment, а пользователь выбирает вторую вкладку, SecondFragment. Поскольку SecondFragment никогда раньше не добавлялся, я добавляю его в FragmentManager с помощью FragmentTransaction.add и скрываю FirstFragment с помощью FragmentTransaction.hide. Если пользователь снова выбирает первую вкладку, поскольку FirstFragment ранее был добавлен в FragmentManager, он не добавляется, а только показывает FirstFragment и просто скрывает SecondFragment. И выбор между этими двумя вкладками работает гладко.

Но когда пользователь "обновляет" SwipeRefreshLayout SecondFragment и выбирает первую вкладку, FragmentTransaction ожидает завершения обновления SecondFragment и фиксирует(?) фактическую транзакцию. Странно то, что транзакция немедленно фиксируется наоборот, от обновления FirstFragment до SecondFragment.

Поскольку это происходит в порядке добавления к FragmentManager, я сомневаюсь, что порядок добавления как-то влияет на возврат фрагментов в исходное состояние, и может существовать что-то вроде приоритета потока пользовательского интерфейса, так что это заставляет транзакцию фрагмента выполняться после перехода пользовательского интерфейса добавленного позже фрагмента. заканчивается. Но у меня просто недостаточно подсказок, чтобы решить проблему. Я пробовал прикреплять/отсоединять и возвращать в исходное положение на FragmentTransaction, но не смог решить проблему. Я пробовал и FragmentTransaction.commit, и FragmentTransaction.commitAllowingStateLoss, но ни один из них не решил проблему.

Это мой пример кода MainActivity.

private ArrayList<Integer> mFragmentsStack; // This is simple psuedo-stack which only stores
                                            // the order of fragments stack to collaborate
                                            // when back button is pressed.
private ArrayList<Fragment> mFragmentsList;

@Override
protected void onCreate() {
    mFragmentsStack = new ArrayList<>();
    mFragmentsList = new ArrayList<>();
    mFragmentsList.add(FirstFragment.newInstance());
    mFragmentsList.add(SecondFragment.newInstance());
    mFragmentsList.add(ThirdFragment.newInstance());
    mFragmentsList.add(FourthFragment.newInstance());
    mMainTab = (MainTab) findViewById(R.id.main_tab);
    mMainTab.setOnMainTabClickListener(this);

    int currentTab = DEFAULT_TAB;

    mFragmentsStack.add(currentTab);
    getSupportFragmentManager().beginTransaction().add(R.id.main_frame_layout,
            mFragmentsList.get(currentTab), String.valueOf(currentTab)).commit();
    mMainTab.setCurrentTab(currentTab);
}

// This is custom interface.
@Override
public void onTabClick(int oldPosition, int newPosition) {
    if (oldPosition != newPosition) {
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();

        // First hide the old tab.
        fragmentTransaction.hide(mFragmentsList.get(oldPosition));

        // Recalculate the fragment stack.
        if (mFragmentsStack.contains(newPosition)) {
            mFragmentsStack.remove((Integer) newPosition);
        }
        mFragmentsStack.add(newPosition);

        // Add new fragment if it's not added before, or show new fragment which was already hidden.
        Fragment fragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(newPosition));
        if (fragment != null) {
            fragmentTransaction.show(fragment);
        } else {
            fragmentTransaction.add(R.id.main_frame_layout, mFragmentsList.get(newPosition),
                    String.valueOf(newPosition));
        }

        // Commit the transaction.
        fragmentTransaction.commitAllowingStateLoss();
    }
}

// It mimics the tab behavior of Instagram Android application.
@Override
public void onBackPressed() {
    // If there's only one fragment on stack, super.onBackPressed.
    // If it's not, then hide the current fragment and show the previous fragment.
    int lastIndexOfFragmentsStack = mFragmentsStack.size() - 1;
    if (lastIndexOfFragmentsStack - 1 >= 0) {
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        fragmentTransaction.hide(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack)));
        fragmentTransaction.show(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack - 1)));
        fragmentTransaction.commitAllowingStateLoss();
        mMainTab.setCurrentTab(mFragmentsStack.get(lastIndexOfFragmentsStack - 1));
        mFragmentsStack.remove(lastIndexOfFragmentsStack);
    } else {
        super.onBackPressed();
    }
}

person Lee Han Kyeol    schedule 19.05.2015    source источник
comment
Вы пытались вызвать executePendingTransactions()? Попробуйте это и посмотрите, поможет ли это.   -  person dora    schedule 19.05.2015
comment
@dora Я добавил executePendingTransactions() после операторов фиксации, но это не работает. Мне интересно, правильно ли это место, потому что то, что говорится в документе, похоже, является ответом на мою ситуацию.   -  person Lee Han Kyeol    schedule 20.05.2015


Ответы (1)


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

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        yourSwipeRefreshLayout.setRefreshing(false);
    }
}
person Alexey Prudzila    schedule 26.05.2015
comment
Я думал об этом, setRefreshing в false при смене вкладок, но мне не понравилась идея заставить состояние пользовательского интерфейса отличаться от того, что происходит на самом деле. Однако я не могу найти обходной путь, так что это сделает ближайшую работу. Спасибо. - person Lee Han Kyeol; 28.05.2015
comment
Спаси мой день!! Я использую пейджер с бесконечным просмотром с SwipeRefreshLayout. Индикатор обновления не будет отображаться снова, если я продолжаю прокручивать вправо до того же вида во второй раз => ex 0,1,2,0,1,2 . setRefreshing(false) в destroyItem() и это работает!!! - person JackWu; 13.01.2018