判断Fragment是否对用户可见

转载请标明出处:juejin.im/post/5a30c5… ,谢谢。html

背景

最近在开发过程当中遇到了若干问题,好比android

  1. 页面统计
  2. Banner轮播的启动与暂停
  3. 等等其余自定义需求

在Activity中这些能够很简单的达到目的,可是若是页面中有Fragment,那就没法像Activity那样简单的实现,下面针对Fragment不一样的使用方法进行分析。bash

各类使用方法

1. 在Activity中直接使用

这种状况是最简单的,也就是在Activity使用XML引入,或者使用FragmentManager 的addFragment或者replaceFrament 动态载入。在这种状况下,只要监听Fragment的onResume和onPause方法就可以判断其显隐。在onResume和onPause中间是对用户可见的。app

@Override
public void onResume() {
    super.onResume();
    // TODO now it's visible to user } @Override public void onPause() { super.onPause(); // TODO now it's invisible to user
}
复制代码

2. 使用show和hide来显隐的Fragment

FragmentManager除了addFragment和replaceFragment以外还有showFragment和hideFragment来作Fragment的显隐,这样能够提生页面切换的速度,是一种用空间换时间的方式。可是这样使用的Fragment在被hide的时候是不会调用onPause方法的。由于它只是在屏幕中不可见了,可是没有Pause。这时候咱们须要监听onHiddenChanged方法。ide

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
	if (!hidden) {
		// TODO now it's visible to user } else { // TODO now it's invisible to user
	}
}
复制代码

3. 在ViewPager中的Fragment

如今不少app都会作tab页,而tab页基本都是经过android自带的ViewPager实现的。ViewPager有这样一个特色,当滑到某一个Tab时,它会同时加载这个tab的左右两个tab页,好比我从1页面切换到了2页面,那么3页面的onResume也被调用了,可是3页面其实对用户是不可见的。这时候咱们就须要监听setUserVisibleHint来判断到底对用户是否可见。布局

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
	if (isVisibleToUser) {
		// TODO now it's visible to user } else { // TODO now it's invisible to user
	}
}
复制代码

注意!!!注意!!!注意!!!

在如下几种操做状况下:post

  1. startActivity页面跳转
  2. 按Home键返回主屏
  3. 从其余页面或主屏返回
  4. 等等和上面相似的操做

只要用户进行了以上操做,那么上述列出的全部使用方法中,只要是处于同一个Activity中的Fragment,那么无论是否显示,都会且只会调用onResume或onPause方法。ui

好比:

在一个Activity中分别有Fragment A、B,其中在Fragment A中内嵌了Fragment a、b。this

  1. 当返回主屏或者跳转新页面时,Fragment A、B、a、b四个均会执行onPause方法,而onHiddenChanged和setUserVisibleHint两个方法不会被执行。
  2. 一样,当返回Activity页面时,Fragment A、B、a、b四个均会执行onResume方法,而onHiddenChanged和setUserVisibleHint两个方法不会被执行。

正是由于上述问题的存在,因此须要onHiddenChanged、setUserVisibleHint、onResume、onPause四个方法相互结合一块儿来判断。spa

代码以下

public abstract class BaseFrameFragment extends Fragment {

    public BaseFrameActivity activity;

    private boolean isFirstCreate;// 是不是第一次建立

    private boolean isVisibleToUser;// 当前可见状态
    private boolean isLastVisibleToUser;// 最后一次可见状态(onPause前的最后一次状态)

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        LogUtil.i("onAttach:" + getFragmentName());
        FragmentActivity activity = getActivity();
        if (activity instanceof BaseFrameActivity) {
            this.activity = (BaseFrameActivity) activity;
        } else {
            throw new IllegalArgumentException("Activity 必须继承 BaseFrameActivity");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        LogUtil.i("onCreateView:" + getFragmentName());
        View layout_root = View.inflate(activity, getContentViewResourceId(), null);
        initData(getArguments());
        initView(layout_root);
        loadData();
        setListener();
        isFirstCreate = true;
        return layout_root;
    }

    /**
     * 使用showFragment和hideFragment来作Fragment的显隐时判断Fragment是否可见
     *
     * @param hidden 是否隐藏
     */
    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        LogUtil.i("onHiddenChanged:" + getFragmentName() + " " + hidden);
        isLastVisibleToUser = !hidden;
        onVisibleToUser(isLastVisibleToUser);
        setChildVisibleToUser(isLastVisibleToUser);
    }

    /**
     * 使用ViewPager来作Fragment的显隐时判断Fragment是否可见
     *
     * @param isVisibleToUser 是否可见
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (activity == null) {
            LogUtil.i("setUserVisibleHint:" + isVisibleToUser);
            return;
        }
        LogUtil.i("setUserVisibleHint:" + getFragmentName() + " " + isVisibleToUser);
        isLastVisibleToUser = isVisibleToUser;
        onVisibleToUser(isLastVisibleToUser);
        setChildVisibleToUser(isLastVisibleToUser);
    }

    /**
     * 在Activity使用XML引入,或者使用FragmentManager 的addFragment或者replaceFragment 动态载入时判断Fragment是否可见
     * startActivity切换页面或者Home键切入后台后回到原页面也会调用此方法
     */
    @Override
    public void onResume() {
        super.onResume();
        LogUtil.i("onResume:" + getFragmentName());
        // 第一次建立且显示给用户(ViewPager) 或 回到原页面前可见状态且ParentFragment isLastVisibleToUser状态
        if ((isFirstCreate && getUserVisibleHint()) || (isLastVisibleToUser && getParentFragmentLastVisibleToUser())) {
            onVisibleToUser(true);
        }
    }

    /**
     * 在Activity使用XML引入,或者使用FragmentManager 的addFragment或者replaceFragment 动态载入时判断Fragment是否可见
     * startActivity切换页面或者Home键切入后台也会调用此方法
     */
    @Override
    public void onPause() {
        super.onPause();
        LogUtil.i("onPause:" + getFragmentName());
        if (isLastVisibleToUser) {
            onVisibleToUser(false);
        }
    }

    /**
     * 获取ParentFragment isLastVisibleToUser状态(没有则为true)
     *
     * @return ParentFragment isLastVisibleToUser
     */
    private boolean getParentFragmentLastVisibleToUser() {
        Fragment parentFragment = getParentFragment();
        if (parentFragment != null) {
            if (parentFragment instanceof BaseFrameFragment) {
                BaseFrameFragment frameFragment = (BaseFrameFragment) parentFragment;
                return frameFragment.isLastVisibleToUser;
            }
        }
        return true;
    }

    /**
     * 设置子Fragment显示状态
     *
     * @param isVisibleToUser isVisibleToUser
     */
    private void setChildVisibleToUser(boolean isVisibleToUser) {
        List<Fragment> fragmentList = getChildFragmentManager().getFragments();
        if (!BaseUtils.isEmptyList(fragmentList)) {
            for (Fragment fragment : fragmentList) {
                if (fragment instanceof BaseFrameFragment) {
                    BaseFrameFragment frameFragment = (BaseFrameFragment) fragment;
                    if (frameFragment.isLastVisibleToUser) {
                        frameFragment.onVisibleToUser(isVisibleToUser);
                    }
                }
            }
        }
    }

    public abstract String getFragmentName();

    /**
     * 获取根布局ResourceId
     *
     * @return 根布局ResourceId
     */
    public abstract int getContentViewResourceId();

    /**
     * 初始化数据,主要包括拆包从activity传递过来的参数,适配器初始化,集合初始化等,不可进行view的操做
     *
     * @param arguments 接收到的从其余地方传递过来的参数
     */
    public abstract void initData(Bundle arguments);

    /**
     * 初始化View
     *
     * @param layout_root Fragment View
     */
    public abstract void initView(View layout_root);

    /**
     * 加载数据,在onCreateView方法中调用能够直接理解为加载数据,方法中能够进行view的操做
     */
    public abstract void loadData();

    /**
     * 设置监听
     */
    public abstract void setListener();

    /**
     * 对用户可见/不可见时执行的操做(相似Activity的onResume/onPause方法)
     *
     * @param isVisibleToUser 是否对用户显示可见
     */
    public void onVisibleToUser(boolean isVisibleToUser) {
        if (this.isVisibleToUser == isVisibleToUser) {
            return;
        }
        LogUtil.i("onVisibleToUser:" + getFragmentName() + " " + isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        isFirstCreate = false;
        if (isVisibleToUser) {
            isLastVisibleToUser = true;
        }
    }

}

复制代码

具体使用

public class A_TempFragment extends BaseFrameFragment {

    @Override
    public String getFragmentName() {
        return getString(R.string.app_name);
    }

    @Override
    public int getContentViewResourceId() {
        return R.layout.activity_base;
    }

    @Override
    public void initData(Bundle arguments) {

    }

    @Override
    public void initView(View layout_root) {
        ButterKnife.bind(this, layout_root);
    }

    @Override
    public void loadData() {

    }

    @Override
    public void setListener() {

    }

    @Override
    public void onVisibleToUser(boolean isVisibleToUser) {
        super.onVisibleToUser(isVisibleToUser);
        if (isVisibleToUser) {
            // TODO now it's visible to user } else { // TODO now it's invisible to user
        }
    }
    
}
复制代码

目前在Activity嵌入Fragment,Fragment内嵌ViewPager+Fragment使用中,一切正常 欢迎一块儿讨论

参考资料

www.cnblogs.com/dongweiq/p/…

相关文章
相关标签/搜索