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

Понимание фрагментов backstack

Итак, есть некоторые подобные вопросы, но я не нашел ни одного, кто решает эту проблему. Официальная официальная документация по Android для кажется интуитивной, но когда я реализую приложение с более сложным рабочим процессом, фрагменты backstack становятся беспорядочными, и начинает происходить странный материал. Я разработал скелет для простых приложений, с идеей одного действия, к которому можно получить доступ к его фрагментам, чтобы запустить другие фрагменты. Вот как я это сделал:

1- Я позволю своей основной деятельности реализовать интерфейс под названием "FragmentDelegate"

public interface FragmentDelegate {
    public void startFragment(CCFragment fragment, boolean addToBackStack);
}

2- Реализация метода startFrargment:

@Override
public void startFragment(CCFragment fragment, boolean addToBackStack) {

    FragmentManager fragmentManager = getSupportFragmentManager();

    fragment.setFragmentDelegate(this);
    FragmentTransaction fragmentTransaction = fragmentManager
            .beginTransaction();

    fragmentTransaction.setCustomAnimations(R.anim.slide_in_right,
            R.anim.slide_out_left, R.anim.slide_in_left,
            R.anim.slide_out_right);

    fragmentTransaction.replace(CONTENT_VIEW_ID, fragment,
            "callerFragmentClassName");
    if (addToBackStack)
        fragmentTransaction.addToBackStack("callerFragmentClassName");
    fragmentTransaction.commitAllowingStateLoss();

}

Приятная вещь в этом, я могу позвонить из любого фрагмента:

mFragmentDelegate.startFragment(aNewFragment, addToBackStack);

Теперь подумайте о следующем сценарии:

Я начинаю свою деятельность с исходного фрагмента, скажем, фрагмент A. Из фрагмента A я вызываю операцию "Камера" для получения результата. Когда результат достигнет, я начинаю Fragment B (добавление A к стопке). Начиная с B, я начинаю Fragment C без, добавляя B в backstack. Итак, мы имеем это в задней части:

[A] [C]

Если я нажму кнопку "Назад", я вернусь к A. Если я повторю этот процесс, backstack перепутался, и когда я нажимаю, он снова и снова возвращает меня к фрагменту C...

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

4b9b3361

Ответ 1

Объяснение:

Когда FragmentManager возвращает сохраненные FragmentTransactions (например, пользователь нажимает кнопку "Назад" или вы вызываете какой-то поп-метод на нем), он выполняет противоположное действие, сохраненное в сохраненном FragmentTransaction. Вы можете увидеть точный код здесь, это довольно просто.

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

[A] [B]

FragmentManager знает, что нужно удалить экземпляр [B] Fragment и добавить [A] в поп-операцию. Проблема в том, что вы заменили [B] на [C]:

[A] [C]

К сожалению, сохраненная запись Fragment BackStack не знает о [C]. Поэтому во время поп-операции FragmentManager снова добавит [A], не найдет [B], чтобы он ничего не делал, и оставьте [C] там, где он есть.

Решение

Одним из возможных решений этой проблемы является использование дочерних фрагментов. Фрагмент-A - фрагмент верхнего уровня, но фрагмент-B и фрагмент-C являются дочерними фрагментами WrapperFragment.

В основном, когда вы переходите к фрагменту-B, вы заменяете Fragment-A с помощью WrapperFragment в сохраненной транзакции:

[A] [[B]]

Затем, когда пользователь переходит к фрагменту-C, вы заменяете WrapperFragment [B] на [C]:

[A] [[C]]

Когда пользователь нажимает кнопку "Назад", мы вернемся к фрагменту-A:

[А]

Demo

Я собрал проект GitHub, чтобы продемонстрировать эту технику.

Ответ 2

Я не могу понять, как вы закончили с появлением фрагментов C снова и снова без полной картины того, что вы сделали, но вот что вы ошибались в отношении backstack:

  • Запись
  • BackStack фактически сохраняет текущее состояние целого FragmentManager, а не только один фрагмент. То есть если вы выполняете несколько операций с несколькими фрагментами в одной транзакции и вызов addToBackStack(), вы сохраните состояние всех фрагментов в предстоящая транзакция.

  • Когда вы вызываете addToBackStack(), вы фактически добавляете next состояние в заднюю часть, то есть, если вы вызвали addToBackStack(), когда вы добавили фрагмент, у вас есть состояние с B и состоянием с A позади него - [A] [B], а не [A] [C].

Я рекомендую вам использовать этот код  и попробуйте все с отладчиком, глядя на состояние   FragmentManager объект:

    int count = fragmentManager.getBackStackEntryCount();
    fragmentTransaction.addToBackStack(String.valueOf(count));

Таким образом, вы сможете отслеживать, что действительно происходит в вашем приложении.

Ответ 3

Прежде всего помните:

 .replace() = .remove().add()

некоторые возможные решения

  public void onBackPressed(){
  // here you have to remove your last fragment.
  super.onBackPressed();
}

///////////////////////////////////////////////////////////////////////////////////////////////

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        this.finish();
        return false;
    } else {
        getSupportFragmentManager().popBackStack();
        removeCurrentFragment();
        return false;
    }
}

  return super.onKeyDown(keyCode, event);
}


public void removeCurrentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFrag =      getSupportFragmentManager().findFragmentById(R.id.detailFragment);

if (currentFrag != null)
    transaction.remove(currentFrag);

transaction.commit();
}

////////////////////////////////////////////////////////////////////////////////////////

для получения дополнительной информации о backstack фрагментов Проверить здесь и Здесь

Ответ 4

Это может показаться не решением, но я думаю, что лучше, если вы не используете фрагменты в таких ситуациях. Сначала, имея только одно действие и заменяя фрагменты по запросу, кажется отличной идеей, но когда вы пытаетесь создать приложение таким образом, все становится беспорядочным. (Я был там, и я говорю по опыту). Управление BackStack самостоятельно - это только одна из проблем. По мере того, как вы продвигаетесь дальше, вы оказываетесь в одной активности с таким количеством связанных с ней кода, что совсем не круто!

Я предлагаю вам создать одно действие для каждого фрагмента, которое у вас есть, и просто поместить в него свой фрагмент. В некоторых случаях ваши действия могут иметь несколько фрагментов (скажем, планшеты или ландшафтный режим) и один в другом случае (например, портретный режим). Но вам больше не нужно использовать метод замены.

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