问题: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
    }
}

其他回答

我们有一个MVP的特殊情况,其中片段需要通知演示者视图已可见,并且演示者由Dagger在fragment.onAttach()中注入。

setUserVisibleHint()还不够,我们检测到需要解决的3种不同情况(提到onAttach(),以便您知道演示者何时可用):

片段刚刚创建。系统进行以下调用:setUserVisibleHint()//在片段的生命周期调用之前,因此演示者为空onAttach()...打开恢复()片段已创建,并按下主页按钮。将应用程序恢复到前台时,这称为:打开恢复()方向更改:onAttach()//演示者可用打开恢复()setUserVisibleHint()

我们只希望可见性提示到达演示者一次,所以我们是这样做的:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_list, container, false);
    setHasOptionsMenu(true);

    if (savedInstanceState != null) {
        lastOrientation = savedInstanceState.getInt(STATE_LAST_ORIENTATION,
              getResources().getConfiguration().orientation);
    } else {
        lastOrientation = getResources().getConfiguration().orientation;
    }

    return root;
}

@Override
public void onResume() {
    super.onResume();
    presenter.onResume();

    int orientation = getResources().getConfiguration().orientation;
    if (orientation == lastOrientation) {
        if (getUserVisibleHint()) {
            presenter.onViewBecomesVisible();
        }
    }
    lastOrientation = orientation;
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (presenter != null && isResumed() && isVisibleToUser) {
        presenter.onViewBecomesVisible();
    }
}

@Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt(STATE_LAST_ORIENTATION, lastOrientation);
}

我发现只有在片段真正可见的情况下才调用onCreateOptionsMenu和onPrepareOptionsMenus方法。我找不到任何这样的方法,我也尝试了OnPageChangeListener,但它不适用于这种情况,例如,我需要在onCreate方法中初始化一个变量。

因此,这两种方法可以作为解决此问题的变通方法,特别适用于小而短的工作。

我认为,这是更好的解决方案,但不是最好的。我会使用这个,但同时等待更好的解决方案。

当做

注意,在活动/片段停止时不会调用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
    }
}

这似乎恢复了正常的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
}

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

计时器总是在用户看到片段之前启动。这是因为片段中的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等不兼容。