У меня есть несколько фрагментов внутри действия. При нажатии кнопки я начинаю новый фрагмент, добавляя его в стопку. Я, естественно, ожидал, что метод onPause()
текущего фрагмента и onResume()
нового фрагмента будет вызван. Ну, этого не происходит.
LoginFragment.java
public class LoginFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.login_fragment, container, false);
final FragmentManager mFragmentmanager = getFragmentManager();
Button btnHome = (Button)view.findViewById(R.id.home_btn);
btnHome.setOnClickListener(new View.OnClickListener() {
public void onClick(View view){
HomeFragment fragment = new HomeFragment();
FragmentTransaction ft2 = mFragmentmanager.beginTransaction();
ft2.setCustomAnimations(R.anim.slide_right, R.anim.slide_out_left
, R.anim.slide_left, R.anim.slide_out_right);
ft2.replace(R.id.middle_fragment, fragment);
ft2.addToBackStack("");
ft2.commit();
}
});
}
@Override
public void onResume() {
Log.e("DEBUG", "onResume of LoginFragment");
super.onResume();
}
@Override
public void onPause() {
Log.e("DEBUG", "OnPause of loginFragment");
super.onPause();
}
}
HomeFragment.java
public class HomeFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.login_fragment, container, false);
}
@Override
public void onResume() {
Log.e("DEBUG", "onResume of HomeFragment");
super.onResume();
}
@Override
public void onPause() {
Log.e("DEBUG", "OnPause of HomeFragment");
super.onPause();
}
}
Я ожидал, что
- При нажатии кнопки LoginFragment заменяется на
HomeFragment,
onPause()
LoginFragment и onResume()
HomeFragment получает вызов
- Когда нажата кнопка назад, HomeFragment выгружается, а LoginFragment -
и
onPause()
HomeFragment и onResume()
LoginFragment
получает вызов.
Что я получаю,
- При нажатии кнопки HomeFragment правильно заменяется
LoginFragment, onResume() HomeFragment вызывается, но onPause()
LoginFragment никогда не вызывается.
- При возврате назад HomeFragment отображается правильно, чтобы показать
LoginFragment, onPause() HomeFragment вызывается, а onResume()
LoginFragment никогда не будет вызван.
Это обычное поведение? Почему onResume()
LoginFragment не вызывается, когда я нажимаю кнопку "Назад".
Ответ 1
Фрагменты onResume()
или onPause()
будут вызываться только тогда, когда вызываются действия onResume()
или onPause()
.
Они плотно связаны с Activity
.
Прочтите Обработка раздела жизненного цикла фрагмента этой статьи.
Ответ 2
- Поскольку вы использовали
ft2.replace()
, FragmentTransaction.remove()
вызывается метод Loginfragment
.
См. .
Итак, onStop()
of Loginfragment
будет вызываться вместо onPause()
. (Как новый
фрагмент полностью заменяет старый).
- Но так как у вас есть
используется
ft2.addtobackstack()
, состояние Loginfragment
будет
сохранен как комплект, и когда вы нажимаете кнопку "Назад" от HomeFragment
,
onViewStateRestored()
, за которым следует onStart()
of
Loginfragment
. Поэтому в итоге onResume()
не будет вызываться.
Ответ 3
Здесь моя более надежная версия ответа Gor (используя fragments.size() ненадежна из-за того, что размер не уменьшается после того, как фрагмент выскочил)
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if (getFragmentManager() != null) {
Fragment topFrag = NavigationHelper.getCurrentTopFragment(getFragmentManager());
if (topFrag != null) {
if (topFrag instanceof YourFragment) {
//This fragment is being shown.
} else {
//Navigating away from this fragment.
}
}
}
}
});
И метод getCurrentTopFragment:
public static Fragment getCurrentTopFragment(FragmentManager fm) {
int stackCount = fm.getBackStackEntryCount();
if (stackCount > 0) {
FragmentManager.BackStackEntry backEntry = fm.getBackStackEntryAt(stackCount-1);
return fm.findFragmentByTag(backEntry.getName());
} else {
List<Fragment> fragments = fm.getFragments();
if (fragments != null && fragments.size()>0) {
for (Fragment f: fragments) {
if (f != null && !f.isHidden()) {
return f;
}
}
}
}
return null;
}
Ответ 4
Если вы действительно хотите заменить фрагмент внутри другого фрагмента, вы должны использовать Вложенные фрагменты.
В вашем коде вы должны заменить
final FragmentManager mFragmentmanager = getFragmentManager();
с
final FragmentManager mFragmentmanager = getChildFragmentManager();
Ответ 5
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
List<Fragment> fragments = getFragmentManager().getFragments();
if (fragments.size() > 0 && fragments.get(fragments.size() - 1) instanceof YoureFragment){
//todo if fragment visible
} else {
//todo if fragment invisible
}
}
});
но будьте осторожны, если видится более одного фрагмента
Ответ 6
У меня есть код, очень похожий на ваш, и если он работает onPause() и onResume(). При изменении фрагмента эти функции активируются соответственно.
Код в фрагменте:
@Override
public void onResume() {
super.onResume();
sensorManager.registerListener(this, proximidad, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this, brillo, SensorManager.SENSOR_DELAY_NORMAL);
Log.e("Frontales","resume");
}
@Override
public void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
Log.e("Frontales","Pause");
}
Журнал при изменении фрагмента:
05-19 22:28:54.284 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:28:57.002 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:28:58.697 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:00.840 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:29:02.248 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:03.718 2371-2371/madi.cajaherramientas E/Frontales: Pause
Фрагмент onCreateView:
View rootView;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.activity_proximidad, container, false);
ButterKnife.bind(this,rootView);
inflar();
setTextos();
return rootView;
}
Действие при возврате импульса (в том случае, когда я загружаю фрагмент):
@Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
Ответ 7
Вы просто не можете добавить фрагмент в фрагмент. Это должно произойти в FragmentActivity. Я предполагаю, что вы создаете LoginFragment в FragmentActivity, поэтому, чтобы получить эту работу, вам нужно добавить HomeFragment через FragmentActivity, когда логин закрывается.
Общий момент заключается в том, что вам нужен класс FragmentActivity, из которого вы добавляете каждый фрагмент в FragmentManager. невозможно сделать это внутри класса Fragment.
Ответ 8
Если вы добавите фрагмент в XML, вы не сможете их динамически менять. Что происходит, они чрезмерно, поэтому события не срабатывают, как можно было бы ожидать. Этот вопрос задокументирован в этом вопросе. FragmenManager replace делает наложение
Поверните middle_fragment в FrameLayout и загрузите его, как показано ниже, и ваши события будут срабатывать.
getFragmentManager().beginTransation().
add(R.id.middle_fragment, new MiddleFragment()).commit();
Ответ 9
Вы можете попробовать это,
Шаг1: переопределите метод Tabselected в вашей активности
@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
try {
if(MyEventsFragment!=null && tab.getPosition()==3)
{
MyEvents.fragmentChanged();
}
}
catch (Exception e)
{
}
mViewPager.setCurrentItem(tab.getPosition());
}
Шаг 2. Используя статический метод, сделайте то, что вы хотите в своем фрагменте,
public static void fragmentChanged()
{
Toast.makeText(actvity, "Fragment Changed", Toast.LENGTH_SHORT).show();
}
Ответ 10
Что я делаю в дочернем фрагменте:
@Override
public void onDetach() {
super.onDetach();
ParentFragment pf = (ParentFragment) this.getParentFragment();
pf.onResume();
}
И затем переопределите onResume на ParentFragment
Ответ 11
Фрагмент всегда должен быть встроен в действие, а жизненный цикл фрагмента напрямую зависит от жизненного цикла хоста. Например, когда действие приостановлено, так же как и все фрагменты в нем, и когда действие уничтожается, так же как и все фрагменты
Ответ 12
onPause()
работает в классе активности, который вы можете использовать:
public void onDestroyView(){
super.onDestroyView
}
для той же цели..
Ответ 13
Выполните следующие шаги, и вы получите нужный ответ
1- Для обоих фрагментов создайте новый абстрактный родительский.
2- Добавьте пользовательский абстрактный метод, который должен быть реализован обоими.
3- Вызовите его из текущего экземпляра перед заменой на второй.
Ответ 14
Исходя из ответа @Gor я написал подобное в Kotlin. Поместите этот код в onCreate()
действия. Это работает для одного видимого фрагмента. Если у вас есть ViewPager
с фрагментами, он будет вызывать фрагмент ViewPager
, а не предыдущий.
supportFragmentManager.addOnBackStackChangedListener {
supportFragmentManager.fragments.lastOrNull()?.onResume()
}
Прочитав https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6, я понял, что во многих ситуациях было бы лучше добавлять новые фрагменты с replace
, а не add
. Так что необходимость в onResume
в некоторых случаях отпадет.
Ответ 15
Вызов ft.replace
должен инициировать onPause (замещенного фрагмента) и onResume (замещающего фрагмента).
Я заметил, что ваш код раздувает login_fragment
в домашнем фрагменте, а также не возвращает представления в onCreateView. Если это опечатки, можете ли вы показать, как эти фрагменты вызываются из вашей деятельности?
Ответ 16
Хотя с другим кодом я столкнулся с той же проблемой, что и OP, потому что изначально использовал
fm.beginTransaction()
.add(R.id.fragment_container_main, fragment)
.addToBackStack(null)
.commit();
вместо
fm.beginTransaction()
.replace(R.id.fragment_container_main, fragment)
.addToBackStack(null)
.commit();
При "замене" первый фрагмент воссоздается, когда вы возвращаетесь из второго фрагмента, и поэтому также вызывается onResume().
Ответ 17
Я использую в своей деятельности - KOTLIN
supportFragmentManager.addOnBackStackChangedListener {
val f = supportFragmentManager.findFragmentById(R.id.fragment_container)
if (f?.tag == "MyFragment")
{
//doSomething
}
}
Ответ 18
При создании транзакции фрагмента обязательно добавьте следующий код.
// 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);
Также убедитесь, что для фиксации транзакции после добавления ее в backstack