转载请标明出处:juejin.im/post/5a30c5… ,谢谢。
背景
最近在开发过程中遇到了若干问题,比如
- 页面统计
- Banner轮播的启动与暂停
- 等等其他自定义需求
在Activity中这些可以很简单的达到目的,但是如果页面中有Fragment,那就无法像Activity那样简单的实现,下面针对Fragment不同的使用方法进行分析。
各种使用方法
1. 在Activity中直接使用
这种情况是最简单的,也就是在Activity使用XML引入,或者使用FragmentManager 的addFragment或者replaceFrament 动态载入。在这种情况下,只要监听Fragment的onResume和onPause方法就能够判断其显隐。在onResume和onPause中间是对用户可见的。
@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方法。
@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
}
}
复制代码
注意!!!注意!!!注意!!!
在以下几种操作情况下:
- startActivity页面跳转
- 按Home键返回主屏
- 从其他页面或主屏返回
- 等等和上面类似的操作
只要用户进行了以上操作,那么上述列出的所有使用方法中,只要是处于同一个Activity中的Fragment,那么不管是否显示,都会且只会调用onResume或onPause方法。
比如:
在一个Activity中分别有Fragment A、B,其中在Fragment A中内嵌了Fragment a、b。
- 当返回主屏或者跳转新页面时,Fragment A、B、a、b四个均会执行onPause方法,而onHiddenChanged和setUserVisibleHint两个方法不会被执行。
- 同样,当返回Activity页面时,Fragment A、B、a、b四个均会执行onResume方法,而onHiddenChanged和setUserVisibleHint两个方法不会被执行。
正是因为上述问题的存在,所以需要onHiddenChanged、setUserVisibleHint、onResume、onPause四个方法相互结合一起来判断。
代码如下
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使用中,一切正常 欢迎一起讨论