问题:ViewPager中的Fragment onResume()在片段实际可见之前被激发。

例如,我有2个带有ViewPager和FragmentPagerAdapter的片段。第二个片段仅对授权用户可用,我需要在片段可见时要求用户登录(使用警告对话框)。

但是,当第一个片段可见时,ViewPager创建第二个片段,以便缓存第二个碎片,并在用户开始滑动时使其可见。

因此,onResume()事件在第二个片段可见之前很久就被激发了。这就是为什么我试图找到一个事件,当第二个片段变得可见时,该事件会触发,以便在适当的时候显示对话框。

如何做到这一点?


当前回答

注意,在活动/片段停止时不会调用setUserVisibleHint(false)。您仍然需要检查启动/停止以正确注册/注销任何侦听器等。

此外,如果片段以不可见状态开始,则会得到setUserVisibleHint(false);您不想在那里注销,因为在这种情况下,您以前从未注册过。

@Override
public void onStart() {
    super.onStart();

    if (getUserVisibleHint()) {
        // register
    }
}

@Override
public void onStop() {
    if (getUserVisibleHint()) {
        // unregister
    }

    super.onStop();
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (isVisibleToUser && isResumed()) {
        // register

        if (!mHasBeenVisible) {
            mHasBeenVisible = true;
        }
    } else if (mHasBeenVisible){
        // unregister
    }
}

其他回答

在片段中添加以下代码

@Override
public void setMenuVisibility(final boolean visible) 
 {
    super.setMenuVisibility(visible);
    if (visible && isResumed()) 
     {

     }
}

更新:Android支持库(rev 11)最终修复了用户可见提示问题,现在如果您将支持库用于片段,那么您可以安全地使用getUserVisibleHint()或重写setUserVisibleHint()来捕获gorn的答案所描述的更改。

UPDATE 1 getUserVisibleHint()有一个小问题。默认情况下,该值为true。

// Hint provided by the app that this fragment is currently visible to the user.
boolean mUserVisibleHint = true;

因此,在调用setUserVisibleHint()之前尝试使用它可能会出现问题。作为解决方法,您可以像这样在onCreate方法中设置值。

public void onCreate(@Nullable Bundle savedInstanceState) {
    setUserVisibleHint(false);

过时的答案:

在大多数使用情况下,ViewPager一次只显示一个页面,但如果您在Android支持库r11之前的版本中使用FragmentStatePagerAdapter,则预缓存的片段也会处于“可见”状态(实际上不可见)。

我覆盖:

public class MyFragment extends Fragment {
    @Override
    public void setMenuVisibility(final boolean visible) {
        super.setMenuVisibility(visible);
        if (visible) {
            // ...
        }
    }
   // ...
}

为了捕获片段的焦点状态,我认为这是最适合的“可见性”状态,因为ViewPager中只有一个片段可以将其菜单项与父活动的项放在一起。

这似乎恢复了正常的onResume()行为。按下home键离开应用程序,然后重新进入应用程序,效果很好。onResume()不会连续调用两次。

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
        //Only manually call onResume if fragment is already visible
        //Otherwise allow natural fragment lifecycle to call onResume
        onResume();
    }
}

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

    //INSERT CUSTOM CODE HERE
}

只有这对我有用!!而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一起使用,TheisMenuVisible()将始终返回true(onResume()似乎足够了,但我们也希望支持ViewPager)。

setUserVisibleHint已弃用。如果重写此方法,则传入true时实现的行为应移动到Fragment.onResume(),传入false时实现的操作应移动到Fragment.onPause()。

当视图寻呼机中的片段显示在屏幕上供用户查看时,我试图启动计时器时遇到了这个问题。

计时器总是在用户看到片段之前启动。这是因为片段中的onResume()方法在我们看到片段之前被调用。

我的解决方案是检查onResume()方法。当片段8是视图页面的当前片段时,我想调用某个方法“foo()”。

@Override
public void onResume() {
    super.onResume();
    if(viewPager.getCurrentItem() == 8){
        foo();
        //Your code here. Executed when fragment is seen by user.
    }
}

希望这有帮助。我经常看到这个问题。这似乎是我见过的最简单的解决方案。其他很多都与较低的API等不兼容。