众所周知,fragment的onResume()和onPause()方法是和activity绑定在一起的,此时fragment的onResume方法并不能确定在fragment切换前后台时会调用,而app开发中经常会需要在前后台切换时做一些操作,在activity中一般直接在onResume()中操作,而fragment中似乎没有这么方便的原生方法。
和别人合作做某一项目的时候,发现他的fragment中是使用setUserVisibeHint来区分fragment的显示与否,经研究发现,当使用ViewPager+Fragment组合的时候会多次调用setUserVisibleHint方法,然而此方法却有很多缺点,摘一段源码中的note:
* <strong>Note:</strong> This method may be called outside of the fragment lifecycle.
* and thus has no ordering guarantees with regard to fragment lifecycle method calls.
既然有这些缺点,那么在这个方法中来进行数据加载和控件的操作 必然是不安全的
一.简单情景下的封装
于是我们就想要封装一个简单易用的方法来进行数据加载和控件操作
暂时先不管ViewPager+Fragment组合的情况,在一般使用Fragment的情景中
通过 onResume(),onPause(),onHiddenChanged()这三个方法来实现了我们的需求。其中onResume()和onPause()方法是和绑定的activity的生命周期绑定的,另外onHiddenChanged()是在fragment是否可见状态改变的时候调用的,于是就有了以下的解决方案,不再赘述,直接上代码:
public abstract class BaseFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
/**
* fragment可见的时候操作,取代onResume,且在可见状态切换到可见的时候调用
*/
protected void onVisible() {
}
/**
* fragment不可见的时候操作,onPause的时候,以及不可见的时候调用
*/
protected void onHidden() {
}
@Override
public void onResume() {//和activity的onResume绑定,Fragment初始化的时候必调用,但切换fragment的hide和visible的时候可能不会调用!
super.onResume();
if (isAdded() && !isHidden()) {//用isVisible此时为false,因为mView.getWindowToken为null
onVisible();
}
}
@Override
public void onPause() {
if (isVisible())
onHidden();
super.onPause();
}
@Override
public void onHiddenChanged(boolean hidden) {//默认fragment创建的时候是可见的,但是不会调用该方法!切换可见状态的时候会调用,但是调用onResume,onPause的时候却不会调用
super.onHiddenChanged(hidden);
if (!hidden) {
onVisible();
} else {
onHidden();
}
}
代码中的注释已经很详尽了,在fragment可见的时候会调用onVisible()不可见的时候会调用onHidden(),继承这个baseFragment你就可以快乐的使用onVisible()和onHidden()来进行数据加载咯~~
注意:如果您的fragment是配合viewpager使用的,因为viewpager当前页的左右两个fragment都会默认加载,且切换的时候并不会调用onhiddenChanged()方法,所以我上面的方法在viewpager+fragment的组合下有一定的缺陷(例如:viewpager中有两个fragment,当从别的页面回到该viewpager所在页面时,两个fragment都会调用onvisible方法,而在左右滑动两个fragment的时候并不会调用onvisible和onhidden)
因此就有了下面的 加强版 适配ViewPager setUserVisibleHint()的BaseFragment
二.包括ViewPager+Fragment的复杂情景通用封装
代码如下:
public abstract class BaseFragment extends Fragment {
protected final String TAG = this.getClass().getSimpleName();
/**
* Fragment当前状态是否可见
*/
protected boolean isVisible = false;
/**
* Fragment的view是否已创建
*/
protected boolean mIsViewCreated = false;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.xxx,container,false);
System.out.println(TAG + "--onCreateView");
mIsViewCreated = true;
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
System.out.println(TAG + "--onDestroyView");
mIsViewCreated = false;
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println(TAG + "--onDestroy");
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (!mIsViewCreated)//view没有创建的时候不进行操作
return;
if (getUserVisibleHint()) {
if (!isVisible) {//确保在一个可见周期中只调用一次onVisible()
isVisible = true;
onVisible();
}
} else {
if (isVisible) {
isVisible = false;
onHidden();
}
}
}
/**
* 可见
*/
protected void onVisible() {
}
/**
* fragment不可见的时候操作,onPause的时候,以及不可见的时候调用
*/
protected void onHidden() {
}
@Override
public void onResume() {//和activity的onResume绑定,Fragment初始化的时候必调用,但切换fragment的hide和visible的时候可能不会调用!
super.onResume();
System.out.println(TAG + "--Base onResume");
if (isAdded() && !isHidden()) {//用isVisible此时为false,因为mView.getWindowToken为null
onVisible();
isVisible = true;
}
}
@Override
public void onPause() {
System.out.println(TAG + "--Base onPause");
if (isVisible()||isVisible) {
onHidden();
isVisible = false;
}
super.onPause();
}
@Override
public void onHiddenChanged(boolean hidden) {//默认fragment创建的时候是可见的,但是不会调用该方法!切换可见状态的时候会调用,但是调用onResume,onPause的时候却不会调用
super.onHiddenChanged(hidden);
System.out.println(TAG + "--Base onHiddenChanged:" + hidden);
if (!hidden) {
onVisible();
isVisible = true;
} else {
onHidden();
isVisible = false;
}
}
}
如果您有更好的方法,还请指教哦~