Używam pakietu zgodności, aby używać fragmentów z systemem Android 2.2. Używając fragmentów i dodając przejścia między nimi do backstacka, chciałbym uzyskać to samo zachowanie, co onResume aktywności, tj. Zawsze, gdy fragment jest przenoszony na „pierwszy plan” (widoczny dla użytkownika) po wyskoczeniu z backstack, chciałbym, aby jakiś rodzaj wywołania zwrotnego został aktywowany we fragmencie (na przykład w celu wykonania pewnych zmian we współdzielonym zasobie UI).
Widziałem, że nie ma wbudowanego wywołania zwrotnego w ramach fragmentu. czy istnieje dobra praktyka, aby to osiągnąć?
onCreateView
co spowoduje wezwanie do fragmentu po pyknięciu.Odpowiedzi:
Z braku lepszego rozwiązania mam to działające dla mnie: Załóżmy, że mam 1 aktywność (MyActivity) i kilka fragmentów, które zastępują się nawzajem (tylko jeden jest widoczny na raz).
W MyActivity dodaj ten detektor:
getSupportFragmentManager().addOnBackStackChangedListener(getListener());
(Jak widać, używam pakietu zgodności).
implementacja 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()
zostanie wywołana po naciśnięciu przycisku „Wstecz”. jednak kilka zastrzeżeń:FragmentTransaction.addToBackStack()
)źródło
Trochę zmieniłem sugerowane rozwiązanie. U mnie działa lepiej:
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; }
źródło
getFragments()
SupportFragmentManager ... -1: - /Po a
popStackBack()
możesz użyć następującego wywołania zwrotnego:onHiddenChanged(boolean hidden)
w swoim fragmencieźródło
Poniższa sekcja w witrynie Android Developers opisuje mechanizm komunikacji Tworzenie wywołań zwrotnych zdarzeń dla działania . Aby zacytować z niego wiersz:
Edycja: Fragment ma,
onStart(...)
który jest wywoływany, gdy fragment jest widoczny dla użytkownika. Podobnie,onResume(...)
gdy jest widoczny i aktywnie działa. Są one powiązane z ich odpowiednikami w działalności. Krótko mówiąc: użyjonResume()
źródło
Jeśli fragment zostanie umieszczony na backstacku, Android po prostu niszczy jego widok. Sama instancja fragmentu nie jest zabijana. Prostym sposobem na rozpoczęcie powinno być odsłuchanie zdarzenia onViewCreated, czyli umieszczenie tam logiki „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 }
źródło
W mojej aktywności onCreate ()
getSupportFragmentManager().addOnBackStackChangedListener(getListener());
Użyj tej metody, aby złapać określony fragment i wywołać 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; }
źródło
Trochę ulepszone i opakowane w rozwiązanie menedżera.
O czym należy pamiętać. FragmentManager nie jest singletonem, zarządza tylko fragmentami w ramach działania, więc w każdym działaniu będzie nowy. Ponadto, to rozwiązanie jak dotąd nie bierze pod uwagę ViewPagera, który wywołuje metodę setUserVisibleHint () pomagającą kontrolować widoczność fragmentów.
Zapraszam do korzystania z następujących klas, gdy borykasz się z tym problemem (używa iniekcji Dagger2). Aktywne wezwanie:
//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); }
źródło
To jest poprawna odpowiedź, którą możesz wywołać onResume (), pod warunkiem, że fragment jest dołączony do działania. Alternatywnie możesz użyć onAttach i onDetach
źródło
onResume () dla fragmentu działa dobrze ...
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); } ...
źródło
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(); } }
i ostatecznie rozszerz Frament z RootFragment, aby zobaczyć efekt
źródło
Moje obejście polega na uzyskaniu bieżącego tytułu paska akcji we fragmencie przed ustawieniem go na nowy tytuł. W ten sposób po wyskakiwaniu fragmentu mogę wrócić do tego tytułu.
@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(); }
źródło
Użyłem enum
FragmentTags
do zdefiniowania wszystkich moich klas fragmentów.TAG_FOR_FRAGMENT_A(A.class), TAG_FOR_FRAGMENT_B(B.class), TAG_FOR_FRAGMENT_C(C.class)
przekazać
FragmentTags.TAG_FOR_FRAGMENT_A.name()
jako znacznik fragmentu.i teraz
@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; }
źródło