Хорошо обновлять фрагменты вместо создания новых экземпляров?

В example об использовании фрагментов в документах Android, когда приложение находится в режиме "dualview", фрагмент деталей воссоздан когда приложение должно показывать детали для другого заголовка. FragmentTransaction.replace() используется для замены каждого экземпляра фрагмента старых деталей на новый.

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

В случае примера это будет означать метод вдоль строк DetailsFragment.setShownIndex(). Это будет вызываться, переходя в новый индекс заголовка, вместо воссоздания DetailsFragment.

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

Одним из возможных последствий этого может быть то, что, когда фрагмент заголовков находится в состоянии resumed (т.е. на "переднем плане" ), выбор заголовка приведет к вызову DetailsFragment.setShownIndex() в то время, когда детали фрагмент находится в состоянии stopped.

Хорошая идея? Плохая идея?

Спасибо заранее.

Ответ 1

Как вы сказали, основной причиной создания новых экземпляров фрагментов является простота использования обратного стека. Также совершенно безопасно повторно использовать существующий фрагмент (просматривая его с помощью FragmentManager.findFragmentById() или FragmentManager.findFragmentByTag()). Иногда вам нужно хорошо использовать методы фрагмента, такие как isVisible(), isRemoving() и т.д., Поэтому вы не будете незаконно ссылаться на компоненты пользовательского интерфейса, если DetailsFragment - stopped.

В любом случае в вашей предлагаемой однопанельной операции с двумя фрагментами ваш метод setShownIndex может установить личное поле в DetailsFragment, которое загружается в onCreateView или onActivityCreated.

например.

DetailsFragment df = getFragmentManager().findFragmentByTag("details");
if (df != null) {
    df.setShownIndex(getSelectedIndex());
} else {
    df = DetailsFragment.newInstance(getSelectedIndex());
}
fragmentTransaction.replace(R.id.frame, df, "details").commit();

В обоих случаях, если df вновь создается или повторно используется, onCreateView и onActivityCreated будут вызываться, когда DetailsFragment будет добавлен в контейнер.

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

Ответ 2

Я пробовал следующий код, и он работает для меня:

private void replaceFragment(Class fragmentClass, String FRAGMENT_NAME, android.support.v4.app.FragmentManager fragmentManager) {

    Fragment fragment = null;
    String backStateName = fragmentClass.getName(); // nome della classe del Fragment

    Log.d("Fragment: ", "Creazione Fragment: "+backStateName);


    Boolean fragmentExit = isFragmentInBackstack(fragmentManager, backStateName);


    if (fragmentExit) { //Il Fragment è presente nello stacback

        // Fragment exists, go back to that fragment
        //// you can also use POP_BACK_STACK_INCLUSIVE flag, depending on flow
        fragmentManager.popBackStackImmediate(fragmentClass.getName(), 0);

    } else {

        // se non esiste lo aggiungiamo
        try {
            fragment = (Fragment) fragmentClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Inizializzo la transazione del Fragment
        android.support.v4.app.FragmentTransaction ft = fragmentManager.beginTransaction();
        ft.setCustomAnimations(
                R.anim.fragment_slide_left_enter,
                R.anim.fragment_slide_left_exit,
                R.anim.fragment_slide_right_enter,
                R.anim.fragment_slide_right_exit);
        ft.replace(R.id.frameLayout_contentMain, fragment, FRAGMENT_NAME);
        ft.addToBackStack(fragmentClass.getName());
        ft.commit();

        // Recupero il numero di Fragment presenti
        Integer nFragment = fragmentManager.getBackStackEntryCount();

        Log.d("Fragment: ", "Numero di Fragment: "+nFragment);

    }

}

Чтобы определить, находится ли Фрагмент уже в StackBack, выполните эту функцию:

public static boolean isFragmentInBackstack(final android.support.v4.app.FragmentManager fragmentManager, final String fragmentTagName) {
    for (int entry = 0; entry < fragmentManager.getBackStackEntryCount(); entry++) {
        if (fragmentTagName.equals(fragmentManager.getBackStackEntryAt(entry).getName())) {
            return true;
        }
    }
    return false;
}

Я надеюсь, что смогу помочь вам