Я использую пакет совместимости для использования фрагментов с Android 2.2. При использовании фрагментов и добавлении переходов между ними в backstack я хотел бы добиться того же поведения onResume действия, то есть всякий раз, когда фрагмент переводится на «передний план» (видимый для пользователя) после выхода из backstack, я бы хотел, чтобы во фрагменте активировался какой-то обратный вызов (например, для выполнения определенных изменений в общем ресурсе пользовательского интерфейса).
Я видел, что в рамках фрагмента нет встроенного обратного вызова. есть ли хорошая практика для этого?
onCreateView
что будет вызываться для фрагмента после попа.Ответы:
Из-за отсутствия лучшего решения у меня работает следующее: Предположим, у меня есть 1 действие (MyActivity) и несколько фрагментов, которые заменяют друг друга (одновременно виден только один).
В MyActivity добавьте этого слушателя:
getSupportFragmentManager().addOnBackStackChangedListener(getListener());
(Как видите, я использую пакет совместимости).
Реализация getListener:
private OnBackStackChangedListener getListener() { OnBackStackChangedListener result = new OnBackStackChangedListener() { public void onBackStackChanged() { FragmentManager manager = getSupportFragmentManager(); if (manager != null) { MyFragment currFrag = (MyFragment) manager.findFragmentById(R.id.fragmentItem); currFrag.onFragmentResume(); } } }; return result; }
MyFragment.onFragmentResume()
будет вызываться после нажатия "Назад". Однако несколько предостережений:FragmentTransaction.addToBackStack()
)источник
Я немного изменил предложенное решение. У меня лучше работает вот так:
private OnBackStackChangedListener getListener() { OnBackStackChangedListener result = new OnBackStackChangedListener() { public void onBackStackChanged() { FragmentManager manager = getSupportFragmentManager(); if (manager != null) { int backStackEntryCount = manager.getBackStackEntryCount(); if (backStackEntryCount == 0) { finish(); } Fragment fragment = manager.getFragments() .get(backStackEntryCount - 1); fragment.onResume(); } } }; return result; }
источник
getFragments()
в SupportFragmentManager ... -1: - /После a
popStackBack()
вы можете использовать следующий обратный вызов:onHiddenChanged(boolean hidden)
внутри вашего фрагментаисточник
В следующем разделе Android Developers описывается механизм взаимодействия Создание обратных вызовов для действия . Процитировать из него строчку:
Изменить: у фрагмента есть объект,
onStart(...)
который вызывается, когда фрагмент виден пользователю. Точно так же,onResume(...)
когда видно и активно работает. Они привязаны к своим аналогам активности. Вкратце: используйтеonResume()
источник
Если фрагмент помещается в стек, Android просто уничтожает его представление. Сам экземпляр фрагмента не уничтожается. Простой способ начать - это прослушать событие onViewCreated и поместить туда логику onResume ().
boolean fragmentAlreadyLoaded = false; @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { // TODO Auto-generated method stub super.onViewCreated(view, savedInstanceState); if (savedInstanceState == null && !fragmentAlreadyLoaded) { fragmentAlreadyLoaded = true; // Code placed here will be executed once } //Code placed here will be executed even when the fragment comes from backstack }
источник
В моей деятельности onCreate ()
getSupportFragmentManager().addOnBackStackChangedListener(getListener());
Используйте этот метод, чтобы поймать определенный фрагмент и вызвать onResume ()
private FragmentManager.OnBackStackChangedListener getListener() { FragmentManager.OnBackStackChangedListener result = new FragmentManager.OnBackStackChangedListener() { public void onBackStackChanged() { Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container); if (currentFragment instanceof YOURFRAGMENT) { currentFragment.onResume(); } } }; return result; }
источник
Немного улучшено и завернуто в менеджерское решение.
О чем нужно помнить. FragmentManager не синглтон, он управляет только фрагментами в Activity, поэтому в каждом действии он будет новым. Кроме того, это решение пока не учитывает ViewPager, который вызывает метод setUserVisibleHint (), помогающий контролировать видимость фрагментов.
Не стесняйтесь использовать следующие классы при решении этой проблемы (использует инъекцию Dagger2). Вызов в действии:
//inject FragmentBackstackStateManager instance to myFragmentBackstackStateManager FragmentManager fragmentManager = getSupportFragmentManager(); myFragmentBackstackStateManager.apply(fragmentManager);
FragmentBackstackStateManager.java:
@Singleton public class FragmentBackstackStateManager { private FragmentManager fragmentManager; @Inject public FragmentBackstackStateManager() { } private BackstackCallback backstackCallbackImpl = new BackstackCallback() { @Override public void onFragmentPushed(Fragment parentFragment) { parentFragment.onPause(); } @Override public void onFragmentPopped(Fragment parentFragment) { parentFragment.onResume(); } }; public FragmentBackstackChangeListenerImpl getListener() { return new FragmentBackstackChangeListenerImpl(fragmentManager, backstackCallbackImpl); } public void apply(FragmentManager fragmentManager) { this.fragmentManager = fragmentManager; fragmentManager.addOnBackStackChangedListener(getListener()); } }
FragmentBackstackChangeListenerImpl.java:
public class FragmentBackstackChangeListenerImpl implements FragmentManager.OnBackStackChangedListener { private int lastBackStackEntryCount = 0; private final FragmentManager fragmentManager; private final BackstackCallback backstackChangeListener; public FragmentBackstackChangeListenerImpl(FragmentManager fragmentManager, BackstackCallback backstackChangeListener) { this.fragmentManager = fragmentManager; this.backstackChangeListener = backstackChangeListener; lastBackStackEntryCount = fragmentManager.getBackStackEntryCount(); } private boolean wasPushed(int backStackEntryCount) { return lastBackStackEntryCount < backStackEntryCount; } private boolean wasPopped(int backStackEntryCount) { return lastBackStackEntryCount > backStackEntryCount; } private boolean haveFragments() { List<Fragment> fragmentList = fragmentManager.getFragments(); return fragmentList != null && !fragmentList.isEmpty(); } /** * If we push a fragment to backstack then parent would be the one before => size - 2 * If we pop a fragment from backstack logically it should be the last fragment in the list, but in Android popping a fragment just makes list entry null keeping list size intact, thus it's also size - 2 * * @return fragment that is parent to the one that is pushed to or popped from back stack */ private Fragment getParentFragment() { List<Fragment> fragmentList = fragmentManager.getFragments(); return fragmentList.get(Math.max(0, fragmentList.size() - 2)); } @Override public void onBackStackChanged() { int currentBackStackEntryCount = fragmentManager.getBackStackEntryCount(); if (haveFragments()) { Fragment parentFragment = getParentFragment(); //will be null if was just popped and was last in the stack if (parentFragment != null) { if (wasPushed(currentBackStackEntryCount)) { backstackChangeListener.onFragmentPushed(parentFragment); } else if (wasPopped(currentBackStackEntryCount)) { backstackChangeListener.onFragmentPopped(parentFragment); } } } lastBackStackEntryCount = currentBackStackEntryCount; } }
BackstackCallback.java:
public interface BackstackCallback { void onFragmentPushed(Fragment parentFragment); void onFragmentPopped(Fragment parentFragment); }
источник
Это правильный ответ, который вы можете вызвать onResume (), если фрагмент прикреплен к действию. В качестве альтернативы вы можете использовать onAttach и onDetach
источник
onResume () для фрагмента отлично работает ...
public class listBook extends Fragment { private String listbook_last_subtitle; ... @Override public void onCreate(Bundle savedInstanceState) { String thisFragSubtitle = (String) getActivity().getActionBar().getSubtitle(); listbook_last_subtitle = thisFragSubtitle; } ... @Override public void onResume(){ super.onResume(); getActivity().getActionBar().setSubtitle(listbook_last_subtitle); } ...
источник
public abstract class RootFragment extends Fragment implements OnBackPressListener { @Override public boolean onBackPressed() { return new BackPressImpl(this).onBackPressed(); } public abstract void OnRefreshUI(); } public class BackPressImpl implements OnBackPressListener { private Fragment parentFragment; public BackPressImpl(Fragment parentFragment) { this.parentFragment = parentFragment; } @Override public boolean onBackPressed() { ((RootFragment) parentFragment).OnRefreshUI(); } }
и окончательно растяните фрагмент из RootFragment, чтобы увидеть эффект
источник
Мое обходное решение - получить текущий заголовок панели действий во фрагменте перед установкой нового заголовка. Таким образом, как только фрагмент появится, я смогу вернуться к этому заголовку.
@Override public void onResume() { super.onResume(); // Get/Backup current title mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar() .getTitle(); // Set new title ((ActionBarActivity) getActivity()).getSupportActionBar() .setTitle(R.string.this_fragment_title); } @Override public void onDestroy() { // Set title back ((ActionBarActivity) getActivity()).getSupportActionBar() .setTitle(mTitle); super.onDestroy(); }
источник
Я использовал enum
FragmentTags
для определения всех моих классов фрагментов.TAG_FOR_FRAGMENT_A(A.class), TAG_FOR_FRAGMENT_B(B.class), TAG_FOR_FRAGMENT_C(C.class)
передать
FragmentTags.TAG_FOR_FRAGMENT_A.name()
как тег фрагмента.а теперь на
@Override public void onBackPressed(){ FragmentManager fragmentManager = getFragmentManager(); Fragment current = fragmentManager.findFragmentById(R.id.fragment_container); FragmentTags fragmentTag = FragmentTags.valueOf(current.getTag()); switch(fragmentTag){ case TAG_FOR_FRAGMENT_A: finish(); break; case TAG_FOR_FRAGMENT_B: fragmentManager.popBackStack(); break; case default: break; }
источник