Жизненный цикл фрагмента - какой метод вызывается при отображении / скрытии?

99

Я использую следующий метод для переключения между фрагментами (в моем NavigationDrawer), показывая / скрывая их.

protected void showFragment(int container, Fragment fragment, String tag, String lastTag, boolean addToBackStack ) {

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if ( lastTag != null && !lastTag.equals("")) {
            Fragment lastFragment = fragmentManager.findFragmentByTag( lastTag );
            if ( lastFragment != null ) {
                transaction.hide( lastFragment );
            }
        }

        if ( fragment.isAdded() ) {
            transaction.show( fragment );
        }
        else {
            transaction.add( container, fragment, tag );
        }

        if ( addToBackStack ) {
            transaction.addToBackStack( tag );
        }

        transaction.commit();

        // set the active tag
        activeFragTag = tag;
    }

Я не понимаю, какой метод жизненного цикла фрагментов вызывается, когда я его показываю или скрываю? (поскольку нет таких методов, как onShow () или onHide (), я не совсем уверен, что использовать). Я хочу выполнить определенные действия при отображении и скрытии определенного фрагмента.

Филипп Яхода
источник
когда вы вызываете Fragment.show (), то в какой-то момент срабатывает фрагмент onCreate(), за которым onCreateDialog()следуетonCreateView()
Someone Somewhere

Ответы:

122

Подобно жизненному циклу активности, Android вызывает onStart (), когда фрагмент становится видимым.onStop()обычно вызывается, когда фрагмент становится невидимым, но его также можно вызвать позже.

В зависимости от вашего макета Android может вызывать onStart()даже тогда, когда ваш фрагмент еще не виден, но принадлежит видимому родительскому контейнеру. Например, это действительно для того, android.support.v4.view.ViewPagerчто требует от вас переопределения Fragment.setUserVisibleHint()метода. В любом случае, если вам нужно зарегистрировать / отменить регистрацию BroadcastReceivers или других слушателей, вы можете безопасно использовать onStart()иonStop() методы , потому что те будут называться всегда.

Примечание. Некоторые контейнеры фрагментов могут сохранять невидимые фрагменты запущенными. Чтобы справиться с этой ситуацией, вы можете переопределить Fragment.onHiddenChanged(boolean hidden). Согласно документации , фрагмент должен быть как запущенным, так и видимым (не скрытым) , чтобы он был виден пользователю.

Обновление: если вы используете, android.support.v4.widget.DrawerLayoutто фрагмент под ящиком остается включенным и видимым, даже когда ящик открыт. В этом случае вы должны использовать DrawerLayout.setDrawerListener()и слушать onDrawerClosed()и onDrawerOpened()обратные вызовы.

Сергей Шафаренко
источник
14
onStopи onPauseне вызываются, когда фрагмент становится невидимым с помощью транзакции. Тем не менее, onHiddenChangedэто называется, как предполагает ответ s1rius
Йоанн Геркуэ
Это не работает в NavigationDrawer. onHiddenChanged не вызывается в библиотеке поддержки v4 / v11. onStart и onResume также будут вызываться не каждый раз, когда открывается макет ящика.
drdrej
@drdrej Проблема в том, что ящик не скрывает полностью нижний фрагмент. Если вы используете DrawerLayout из библиотеки поддержки, вам необходимо использовать DrawerListener.
сергей шафаренко
70

Я @Override этот метод и решаю свою проблему:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        //do when hidden
    } else {
       //do when show
    }
}
s1rius
источник
1
Пытался не решить, но использование, setUserVisibleHintкак показано в stackoverflow.com/a/18375436/1815624, работает
CrandellWS
36

конечно, вы можете сделать это с помощью @Override:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // Do your Work
        } else {
            // Do your Work
        }
    }
Бирадж Залавадиа
источник
И можно легко узнать, виден ли фрагмент пользователю или нет, позвонивgetUserVisibleHint()
ARiF 01
2
setUserVisibleHint работает с пейджером представлений, но не с обычным контейнером фрагментов.
MikeL
Спасибо, это решает мою проблему :)
РАДЖЕШ КУМАР АРУМУГАМ
Это сработало для меня на ViewPager. onHiddenChanged не сработало.
live-love
Решил мою проблему!
Jad Chahine
3

Поведение пейджера «Фрагмент в представлении» отличается от обычного контейнера фрагментов.

Попробуйте этот код:

    boolean mIsVisibleToUser;

    /**
     * is visible to user
     */
    public void show() {
        //do when show
    }

    /**
     * is invisible to user
     */
    public void hide() {
        //do when gone
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = true;
            show();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = false;
            hide();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isResumed()) {
            if (mIsVisibleToUser != isVisibleToUser) {
                mIsVisibleToUser = isVisibleToUser;
                if (isVisibleToUser) show();
                else hide();
            }
        }
    }

    public boolean isVisibleToUser() {
        return mIsVisibleToUser;
    }
Алан Юань
источник
2

Попробуйте этот код:

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
         onResume();
    }
}

@Override
public void onResume()
{
    super.onResume();
    if (!getUserVisibleHint())
    {
        return;
    }

    //Add your code this section
}
Ахмад Агазаде
источник
2

Вы можете использовать onCreateView (или onActivityCreated) и onHiddenChanged. Используйте onCreateView для первого показа и используйте onHiddenChanged для последующего использования. setMenuVisibility не вызывается для управления транзакциями.

@Override
public View OnCreateView() {
   // fragment will show first
}

@Override
public void onHiddenChanged(boolean hidden) {
    if (!hidden) {
        // fragment will show 
    }
    else {
        // fragment will hide
    }
}
хой
источник
onHiddenChanged () не вызывается с моим фрагментом
matdev
1

Просто попробуйте это в своем setUserVisibleHint ()

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser && getView() != null){
        isActive = true;
        init();
    }else if(isVisibleToUser && getView() == null){
        isActive = false;
    }else{
        isActive = true;
    }
}

И создайте этот код в onCreateView () :

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  if(!isActive){
      init();
  }
}
тростник
источник
isVisibleToUser && getView() != nullработал идеально для меня!
bobby
1

Другой способ вызова метода фрагмента, когда фрагмент виден и вы используете вьюпейджер в действии.

// в первую очередь вы создаете интерфейс

public interface ShowFragmentVisible{
      public void showFragment();}

// После этого этот интерфейс реализуем внутри фрагмента вот так

      public class MyFragment extends Fragment implements 
         ShowFragmentVisible {
            @Override
public void showFragment() {
}

// Теперь переходим к вашему Activity, затем создаем объект интерфейса и вызываем внутри, когда addOnViewpagerListener

   ShowFragmentVisible showFragmentVisible;

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);

    if (fragment instanceof ShowFragmentVisible) {
        showFragmentVisible = (ShowFragmentVisible) fragment;
    }

}
     //your viewpager method
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            if (position==0){
                showFragmentVisible.showFragment();

           }

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });


this is another alternative,but its work for me successfully
Джатин Бансал
источник
0

setUserVisibleHintзвоните раньше onCreateView. и вы не можете обновить любой вид внутри setUserVisibleHint, который я использую

public void setMenuVisibility(final boolean visible)

для видимости, и onHiddenChanged () не вызывается впервые . он вызывается при изменении скрытого состояния. потому что fragment is visible by default. Чтобы использовать этот метод впервые, вам нужно позвонить, mFragmentTransaction.hide(oldFragment)тогда он будет работать

Заметка

если вы хотите использовать подсказку setUserVisible и обновить представление Используйте этот метод

AndroidGeek
источник
0

Конечно, вы можете переопределить setUserVisibleHintили, setMenuVisibilityно если вам нужно получить доступ Contextили Activity, они будут там нулевыми! Существует еще один метод, onStartкоторый всегда имеет контекст под рукой, но он будет вызываться только один раз при создании фрагмента, и если вы начнете перемещаться между своими фрагментами в пейджере, вы увидите, что он не будет вызываться во втором представлении, а затем .

Итак ... что теперь делать?

Обходной путь довольно прост, используйте onStartкак при первом посещении, так и setMenuVisibilityпри последующих. Ваш код, вероятно, будет выглядеть так:

Класс фрагмента:

public class MyFragmentClass{
    private boolean isCurrentVisible = false;
...

@Override
public void onStart() {
    super.onStart();
    if (isCurrentVisible)
        doSth();
}

@Override
public void setMenuVisibility(boolean menuVisible){
    super.setMenuVisibility(menuVisible);
    this.isCurrentVisible = menuVisible;
    if(menuVisible && getContext() != null)
        doSth();
}

Этот способ Contextвсегда будет доступен для doSth()метода.

АмиНадими
источник
0

Только это сработало для меня !! и setUserVisibleHint(...)теперь устарел (я приложил документы в конце), что означает, что некоторые другие ответы устарели ;-)

public class FragmentFirewall extends Fragment {
    /**
     * Required cause "setMenuVisibility(...)" is not guaranteed to be
     * called after "onResume()" and/or "onCreateView(...)" method.
     */
    protected void didVisibilityChange() {
        Activity activity = getActivity();
        if (isResumed() && isMenuVisible()) {
            // Once resumed and menu is visible, at last
            // our Fragment is really visible to user.
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        didVisibilityChange();
    }

    @Override
    public void setMenuVisibility(boolean visible) {
        super.setMenuVisibility(visible);
        didVisibilityChange();
    }
}

Протестировано и работает NaviagationDrawer, isMenuVisible()всегда будет возвращение trueonResume()кажется достаточно, но мы ViewPagerтоже хотим поддержать ).

setUserVisibleHintустарела. При переопределении этого метода поведение, реализованное при передаче, trueдолжно быть перемещено в Fragment.onResume(), а поведение, реализованное при передаче, falseдолжно быть перемещено в Fragment.onPause().

Топ-Мастер
источник