【问题标题】:Fragment lifecycle - which method is called upon show / hide?片段生命周期 - 在显示/隐藏时调用哪个方法?
【发布时间】:2013-08-24 21:06:17
【问题描述】:

我正在使用以下方法通过显示/隐藏片段(在我的 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;
    }

我不清楚的是当我显示或隐藏它时调用 Fragments 生命周期的哪个方法?(因为没有诸如 onShow() 或 onHide() 之类的方法,我不太确定用什么)。我想在显示和隐藏某个 Fragment 时执行特定操作。

【问题讨论】:

  • 当你调用 Fragment.show() 之后,片段会触发onCreate(),然后是onCreateDialog(),然后是onCreateView()

标签: android android-fragments lifecycle fragmenttransaction


【解决方案1】:

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

根据您的布局,即使您的 Fragment 尚不可见,但它属于可见的父容器,Android 也可以调用 onStart()。例如,这对 android.support.v4.view.ViewPager 有效,它要求您覆盖 Fragment.setUserVisibleHint() 方法。在任何情况下,如果您需要注册/取消注册 BroadcastReceivers 或其他侦听器,您可以安全地使用 onStart()onStop() 方法,因为它们将始终被调用。

注意:一些片段容器可以保持不可见片段的启动。要处理这种情况,您可以覆盖Fragment.onHiddenChanged(boolean hidden)。根据documentation,片段必须已启动且可见(不隐藏),才能对用户可见。

更新:如果您使用android.support.v4.widget.DrawerLayout,那么即使抽屉打开,抽屉下方的片段也会保持启动并可见。在这种情况下,您需要使用DrawerLayout.setDrawerListener() 并监听onDrawerClosed()onDrawerOpened() 回调。

【讨论】:

  • onStoponPause 当片段使用事务变得不可见时不会被调用。不过 onHiddenChanged 被称为建议 s1rius 答案
  • 这在 NavigationDrawer 中不起作用。在 v4/v11 支持库上不调用 onHiddenChanged。当抽屉布局打开时,onStart 和 onResume 也不会每次都被调用。
  • @drdrej 问题是抽屉没有完全隐藏下面的片段。如果使用支持库中的 DrawerLayout,则需要使用 DrawerListener。
  • 如前所述,这个答案完全不正确。
【解决方案2】:

我@Override 这个方法并解决我的问题:

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

【讨论】:

【解决方案3】:

当然你可以@Override下面的方法来做到这一点:

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

【讨论】:

  • 通过调用getUserVisibleHint() 可以很容易地知道片段是否对用户可见
  • setUserVisibleHint 适用于视图寻呼机,但不适用于常规片段容器。
  • 谢谢这解决了我的问题:)
  • 这在 ViewPager 上对我有用。 onHiddenChanged 不起作用。
  • 解决了我的问题!
【解决方案4】:

您可以使用“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() 没有被我的片段调用
【解决方案5】:

视图分页器中的片段行为与常规片段容器不同。

试试这个代码:

    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;
    }

【讨论】:

    【解决方案6】:

    试试这个代码:

    @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
    }
    

    【讨论】:

      【解决方案7】:

      只需在你的 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 非常适合我!
      【解决方案8】:

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

      //首先你创建一个界面

      public interface ShowFragmentVisible{
            public void showFragment();}
      

      //然后这个接口就这样在Fragment里面实现

            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
      

      【讨论】:

        【解决方案9】:

        只有这对我有用! 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()

        【讨论】:

          【解决方案10】:

          setUserVisibleHintonCreateView 之前调用。并且您无法更新我使用的 setUserVisibleHint 中的任何视图

          public void setMenuVisibility(final boolean visible)
          

          为了可见性和 onHiddenChanged() 没有第一次调用。它在隐藏状态更改时调用。因为fragment is visible by default。为了第一次实现这个方法你必须调用mFragmentTransaction.hide(oldFragment)然后它会起作用

          注意

          如果你想使用 setUserVisible 提示并更新 View Use this method

          【讨论】:

            【解决方案11】:

            当然您可以覆盖setUserVisibleHintsetMenuVisibility,但如果您需要访问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() 方法。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-12-29
              • 2017-07-02
              • 2014-07-06
              相关资源
              最近更新 更多