具体问题如下:
现有如下结构:
MainActivity(ViewPager)
Fragment1
Fragment2(ViewPager)
Fragment2-1
Fragment2-2
Fragment3
Fragment4
当我们进入MainActivity的时候,MainActivity的viewpager会进行初始化,初始化完毕之后的状态是
MainActivity(ViewPager)
Fragment1.UserVisibleHint = true
Fragment2(ViewPager).UserVisibleHint = false
Fragment2-1.UserVisibleHint = true
Fragment2-2.UserVisibleHint = false
Fragment3.UserVisibleHint = false
Fragment4.UserVisibleHint = false
可以发现Fragment2的UserVisibleHint为false,而他的第一个子fragment2-1的UserVisibleHint为true
而我们实现懒加载时,需要以UserVisibleHint这个属性来判断是否加载数据,因此当我们进入MainActivity的时候,Fragment1会加载数据,Fragment2-1同样也会加载数据,如何避免Fragment2-1不加载数据呢?因为此时我们只想加载Fragment1的数据。Fragment2-1的UserVisibleHint在我们视觉的真正意义上是false。ViewPager并未提供解决此问题的方法,得靠自己来解决。
先来解决初始化时候让Fragment2-1.UserVisibleHint为false
解决思路就是在子Fragment onAttach的时候检查其父Fragment的mUserVisibleHint属性的状态,如果是false就强制将当前子Fragment的mUserVisibleHint属性设置为false并设置一个恢复标记(因为接下来还需要恢复) 然后在父Fragment setUserVisibleHint为true的时候检查其所有子Fragment,有恢复标记的子Fragment,设置其mUserVisibleHint属性为true,看代码:
public class BaseFragment extends Fragment{
private boolean waitingShowToUser;
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//如果自己是显示状态,但父Fragment却是隐藏状态,就把自己也改为隐藏状态,并且设置一个等待显示标记
if(getUserVisibleHint()){
Fragment parentFragment = getParentFragment();
if(parentFragment != null && !parentFragment.getUserVisibleHint()){
waitingShowToUser = true;
super.setUserVisibleHint(false);
}
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(getActivity() != null) {
List<Fragment> childFragmentList = getChildFragmentManager().getFragments();
if (isVisibleToUser) {
// 将所有正等待显示的子Fragment设置为显示状态,并取消等待显示标记
if (childFragmentList != null && childFragmentList.size() > 0) {
for (Fragment childFragment : childFragmentList) {
if (childFragment instanceof BaseFragment) {
BaseFragment childBaseFragment = (BaseFragment)childFragment;
if (childBaseFragment.isWaitingShowToUser()) {
childBaseFragment.setWaitingShowToUser(false);
childFragment.setUserVisibleHint(true);
}
}
}
}
}
}
}
public boolean isWaitingShowToUser() {
return waitingShowToUser;
}
public void setWaitingShowToUser(boolean waitingShowToUser) {
this.waitingShowToUser = waitingShowToUser;
}
}
接下来解决父ViewPager切换的时候同步其子Fragment的UserVisibleHint属性
思路就是在父Fragment setUserVisibleHint为false的时候将其所有mUserVisibleHint为true的子Fragment都强制改为false,然后设置一个恢复标记,然后在setUserVisibleHint为true的时候再恢复,看代码:
public class BaseFragment extends Fragment{
private boolean waitingShowToUser;
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//如果自己是显示状态,但父Fragment却是隐藏状态,就把自己也改为隐藏状态,并且设置一个等待显示标记
if(getUserVisibleHint()){
Fragment parentFragment = getParentFragment();
if(parentFragment != null && !parentFragment.getUserVisibleHint()){
waitingShowToUser = true;
super.setUserVisibleHint(false);
}
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
// 等父Fragment显示
if (isVisibleToUser) {
Fragment parentFragment = getParentFragment();
if (parentFragment != null && !parentFragment.getUserVisibleHint()) {
waitingShowToUser = true;
super.setUserVisibleHint(false);
return;
}
}
if(getActivity() != null) {
List<Fragment> childFragmentList = getChildFragmentManager().getFragments();
if (isVisibleToUser) {
// 将等待显示的子Fragment设置为显示状态,并取消等待显示标记
if (childFragmentList != null && childFragmentList.size() > 0) {
for (Fragment childFragment : childFragmentList) {
if (childFragment instanceof BaseFragment) {
BaseFragment childBaseFragment = (BaseFragment)childFragment;
if (childBaseFragment.isWaitingShowToUser()) {
childBaseFragment.setWaitingShowToUser(false);
childFragment.setUserVisibleHint(true);
}
}
}
}
} else {
// 将正在显示的子Fragment设置为隐藏状态,并设置一个等待显示标记
if (childFragmentList != null && childFragmentList.size() > 0) {
for (Fragment childFragment : childFragmentList) {
if (childFragment instanceof BaseFragment) {
BaseFragment childBaseFragment = (BaseFragment)childFragment;
if (childFragment.getUserVisibleHint()) {
childBaseFragment.setWaitingShowToUser(true);
childFragment.setUserVisibleHint(false);
}
}
}
}
}
}
}
public boolean isWaitingShowToUser() {
return waitingShowToUser;
}
public void setWaitingShowToUser(boolean waitingShowToUser) {
this.waitingShowToUser = waitingShowToUser;
}
}