片段生命周期-在显示/隐藏时调用哪种方法?


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()
有人的地方

Answers:


122

与活动生命周期类似,当片段可见时,Android会调用onStart()onStop()通常在片段变得不可见时调用,但也可以稍后调用。

根据您的布局onStart(),当您的片段尚不可见,但它属于可见的父容器时,Android 甚至可以调用它。例如,这是有效的android.support.v4.view.ViewPager,要求您重写Fragment.setUserVisibleHint()方法。无论如何,如果您需要注册/注销BroadcastReceivers或其他侦听器,则可以安全地使用onStart()onStop()方法,因为它们将始终被调用。

注意:某些片段容器可以使不可见的片段保持启动状态。要处理这种情况,您可以覆盖Fragment.onHiddenChanged(boolean hidden)。根据文档,片段必须既开始又可见(不隐藏),以使用户可见。

更新:如果使用,android.support.v4.widget.DrawerLayout则抽屉下面的碎片将保持启动状态,即使打开抽屉也可见。在这种情况下,您需要使用DrawerLayout.setDrawerListener()和收听onDrawerClosed()onDrawerOpened()回调。


14
onStoponPause当使用事务使片段变得不可见时,不会调用它们。然而,这onHiddenChanged被称为暗示s1rius答案
Yoann Hercouet 2014年

这在NavigationDrawer中不起作用。在v4 / v11支持库上未调用onHiddenChanged。抽屉布局打开时,也不会每次都调用onStart和onResume。
drdrej 2014年

@drdrej问题是抽屉没有完全隐藏下面的片段。如果使用支持库中的DrawerLayout,则需要使用DrawerListener。
谢尔盖·沙法伦卡

69

我@Override此方法并解决了我的问题:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        //do when hidden
    } else {
       //do when show
    }
}

1
尝试没有解决办法,但是使用stackoverflow.com/a/18375436/1815624中setUserVisibleHint显示的方法工作
CrandellWS

36

当然,您可以@Override以下方法来这样做:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // Do your Work
        } else {
            // Do your Work
        }
    }

通过调用getUserVisibleHint()
ARiF'Sep

2
setUserVisibleHint与视图分页器一起使用,但不适用于常规片段容器。
MikeL '17

谢谢你,这解决了我的问题:)
RAJESH KUMAR ARUMUGAM

这在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对我来说很完美!
鲍比

1

当片段可见并且您在活动中使用viewpager时,调用片段方法的另一种方法。

//首先创建一个接口

public interface ShowFragmentVisible{
      public void showFragment();}

//之后,该接口在Fragment中实现

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

//现在进入“活动”,然后创建接口对象并在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提示并更新视图,请使用此方法


0

当然,您可以覆盖setUserVisibleHint或,setMenuVisibility但是如果您需要访问ContextActivity,则它们在那里为空!还有另一种方法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();
    }
}

经过测试并与之一起使用时NaviagationDrawerisMenuVisible()总会返回true(并且onResume()看起来足够了,但我们也希望提供支持ViewPager)。

setUserVisibleHint不推荐使用。如果重写此方法,true则应将传入时实现的行为移至Fragment.onResume(),传入时实现的行为false应移至Fragment.onPause()

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.