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

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

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

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

如何做到这一点?


当前回答

一种简单的实现方法是在进入片段之前检查用户是否已登录。

在MainActivity中,您可以在onNavigationItemSelected方法中执行类似的操作。

 case R.id.nav_profile_side:


                if (User_is_logged_in) {

                    fragmentManager.beginTransaction()
                            .replace(R.id.content_frame
                                    , new FragmentProfile())
                            .commit();
                }else {

                    ShowLoginOrRegisterDialog(fragmentManager);

                }

                break;

然而,如果您使用的是导航抽屉,尽管我们没有转到ProfileFragment,但抽屉中的选择将更改为Profile。

要将选择重置为当前选择,请运行以下代码

        navigationView.getMenu().getItem(0).setChecked(true);

其他回答

package com.example.com.ui.fragment;


import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.com.R;

public class SubscribeFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_subscribe, container, false);
        return view;
    }

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

        if (isVisibleToUser) {
            // called here
        }
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

setUserVisibleHint()有时会在onCreateView()之前调用,有时会在之后调用。

要克服这个问题,您需要在setUserVisibleHint()方法中检查isResumed()。但在本例中,我意识到只有当Fragment恢复并可见时,才会调用setUserVisibleHint(),而不是在Created时。

因此,如果您想在Fragment可见时更新某些内容,请将更新函数放在onCreate()和setUserVisibleHint()中:

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

UPDATE:我仍然意识到myUIUpdate()有时会被调用两次,原因是,如果您有3个选项卡,而这段代码位于第二个选项卡上,当您第一次打开第一个选项卡时,第二个标签也会被创建,即使它不可见,并且会调用myUIUpdate)。然后,当您滑动到第二个选项卡时,将调用if(visible&&isResumed())中的myUIUpdate(),因此,myUIUpdate)可能会在一秒内被调用两次。

另一个问题是!setUserVisibleHint中的visible同时被调用:1)当您退出片段屏幕时;2)在创建片段屏幕之前,当您第一次切换到片段屏幕时。

解决方案:

private boolean fragmentResume=false;
private boolean fragmentVisible=false;
private boolean fragmentOnCreated=false;
...

@Override
public View onCreateView(...){
    ...
    //Initialize variables
    if (!fragmentResume && fragmentVisible){   //only when first time fragment is created
        myUIUpdate();
    }
    ...        
}

@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){   // only at fragment screen is resumed
        fragmentResume=true;
        fragmentVisible=false;
        fragmentOnCreated=true;
        myUIUpdate();
    }else  if (visible){        // only at fragment onCreated
        fragmentResume=false;
        fragmentVisible=true;
        fragmentOnCreated=true;
    }
    else if(!visible && fragmentOnCreated){// only when you go out of fragment screen
        fragmentVisible=false;
        fragmentResume=false;
    }
}

说明:

fragmentResume,fragmentVisible:确保仅在创建片段并可见时才调用onCreateView()中的myUIUpdate(),而不是在恢复时调用。它还解决了当您处于第一个选项卡时的问题,即使第二个选项卡不可见,也会创建它。这解决了这个问题,并检查在onCreate时片段屏幕是否可见。

fragmentOnCreated:确保片段不可见,并且在第一次创建片段时不会被调用。所以现在,这个if子句只在从片段中滑出时被调用。

使现代化您可以像这样将所有这些代码放在BaseFragment代码中,并重写方法。

如何确定片段何时在ViewPager中可见

您可以通过覆盖片段中的setUserVisibleHint来执行以下操作:

public class MyFragment extends Fragment {
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
        }
        else {
        }
    }
}

我们有一个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);
}

setUserVisibleHint(布尔可见)现在已弃用,因此这是正确的解决方案

FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

在版本androidx.fragment:frage:1.1.0的ViewPager2和ViewPager中,您可以使用onPause()和onResume()来确定用户当前可以看到哪个片段。当片段可见时调用onResume(),当片段停止可见时调用onPause()。

要在第一个ViewPager中启用此行为,必须将FragmentPagerAdapter.behavior_RESUME_ONLY_CURRENT_FRAGMENT参数作为FragmentPagerAdapter构造函数的第二个参数传递。