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

Android Honeycomb: Как изменить фрагменты в FrameLayout, не пересоздавая их?

Можно ли переключаться между фрагментами без повторного создания их все время? Если да, то как?

В документации я нашел пример того, как заменить фрагменты.

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

Но я не хочу создавать свои Фрагменты с нуля каждый раз, когда они мне нужны.

Я также нашел этот пример скрытия/показа Фрагменты:

// The content view embeds two fragments; now retrieve them and attach
// their "hide" button.
FragmentManager fm = getFragmentManager();
addShowHideListener(R.id.frag1hide, fm.findFragmentById(R.id.fragment1));
addShowHideListener(R.id.frag2hide, fm.findFragmentById(R.id.fragment2));

Но как мне создать фрагмент с идентификатором вне XML файла?

Я думаю, что это может быть связано с этим вопросом, но ответа нет.:/

Спасибо вам большое заблаговременно, медузы

Edit:

Вот как я это делаю сейчас:

Fragment shown = fragmentManager.findFragmentByTag(shownFragment);

//...

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);

//switch statetement for menu selection, just one example:

SettingsFragment set = (SettingsFragment) fragmentManager.findFragmentByTag(SET);
Toast.makeText(this, "Settings:" + set, Toast.LENGTH_LONG).show();
if (set == null)
{
        set = new SettingsFragment();
        fragmentTransaction.add(R.id.framelayout_content, set, SET);
}
else fragmentTransaction.show(set);
shownFragment = SET;
fragmentTransaction.commit();

Если я вызову настройки, затем что-то еще, а затем вернусь к настройкам, тост сначала даст мне "null" и "Настройки: SettingsFragment {40ef..." second.

Однако, если я заменяю fragmentTransaction.add(R.id.framelayout_content, set, SET); на fragmentTransaction.replace(R.id.framelayout_content, set, SET);, я продолжаю получать "null", "null", "null"... поэтому он не находит фрагмент по тегу.

Edit2:

Добавление fragmentTransaction.addToBackStack(null); сделало трюк.:) Это сохраняет все скрытие/запоминание того фрагмента, который показан в части, поэтому я считаю это самым изящным решением для этого.

Я нашел этот учебник, весьма полезный по этой теме.

Edit3:

Посмотрев на мой код, я понял, что могу избавиться от некоторых частей, поэтому я изменил его на:

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);
Settings set = (Settings) fragmentManager.findFragmentByTag(SET);
if (set == null) set = new Settings();

fragmentTransaction.replace(R.id.framelayout_content, set, SET);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

Однако это вызвало IllegalStateException: Fragment already added, то же самое, что и здесь. Есть ли простой способ предотвратить это? В противном случае, я думаю, что я могу вернуться к биту hide/show.

4b9b3361

Ответ 1

Это может зависеть от того, что вы пытаетесь избежать воссоздания.

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

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

EDIT:

Если у вас просто есть список меню, в котором каждая запись вызывает другой фрагмент в правой панели, то добавление в задний стек не то, что вы хотите. Для этого вы можете уйти с вызовом add(...) на каждом фрагменте вперед и просто скрыть/показать каждый фрагмент по мере необходимости (я не тестировал это). В противном случае я бы предложил сохранить ссылку на каждый фрагмент, вызвать replace(...) при выборе другого пункта меню, чтобы вы не добавляли в задний стек.

Ответ 2

Чтобы избежать

IllegalStateException: фрагмент уже добавлено

Я нашел обходное решение, которое отлично работает для меня: используйте remove(AFrag) и add(BFrag) в вашей транзакции вместо replace().

Похоже, что это ошибка: 4-й комментарий в принятом ответе.

Ответ 3

fragmentTransactionOnClick.setTransition(FragmentTransaction.TRANSIT_EXIT_MASK);

если вы добавите. setTransition.exit transit_exit_mask, тогда предыдущие просмотры не придут

Ответ 4

Я нашел способ, используя функцию "tag":

//...
fragmentTransaction.add(R.id.framelayout_content, fragment1, "foo");
fragmentTransaction.add(R.id.framelayout_content, fragment2, "bar");

//...

fragmentManager.findFragmentByTag("foo");
fragmentManager.findFragmentByTag("bar");

Однако, похоже, это работает асинхронно. Вызов findFragmentByTag сразу после возврата commit null. Только позже, в моем случае в событии OnOptionsItemSelected, фрагменты были найдены.

Существует также функция, называемая findFragmentById(int), но она не очень полезна. Идентификатор - если не указан в XML-макете - тот же, что и контейнер, поэтому в этом случае R.id.framelayout_content. Если позже вы вызовете функцию с этим идентификатором, вы можете получить доступ только к одному из прикрепленных фрагментов. (Я думаю, это последний, но не проверял. Кажется, что он всегда один и тот же.)

Я не сразу увидел способ получить "активный" фрагмент из моего FrameLayout, поэтому я думаю, что где-то я сохраню тег последнего показанного фрагмента.