您的位置:首页 > 其它

Fragment的setUserVisibleHint方法实现懒加载,但setUserVisibleHint 不起作用?

2016-07-17 10:45 453 查看
我们在做应用开发的时候,一个Activity里面可能会以viewpager(或其他容器)与多个Fragment来组合使用,而如果每个fragment都需要去加载数据,或从本地加载,或从网络加载,那么在这个activity刚创建的时候就变成需要初始化大量资源。这样的结果,我们当然不会满意。那么,能不能做到当切换到这个fragment的时候,它才去初始化呢?
答案就在Fragment里的setUserVisibleHint这个方法里。请看关于Fragment里这个方法的API文档:



该方法用于告诉系统,这个Fragment的UI是否是可见的。所以我们只需要继承Fragment并重写该方法,即可实现在fragment可见时才进行数据加载操作,即Fragment的懒加载。根据网友们提供的方法,代码如下(本人稍作修改了下):

import android.os.Bundle;
import android.support.v4.app.Fragment;

/**
* Author: wangjie
* Email: tiantian.china.2@gmail.com
* Date: 1/23/15.
*/
public abstract class BaseLazyFragment extends Fragment {
private static final String TAG = BaseLazyFragment.class.getSimpleName();
private boolean isPrepared;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initPrepare();
}

/**
* 第一次onResume中的调用onUserVisible避免操作与onFirstUserVisible操作重复
*/
private boolean isFirstResume = true;

@Override
public void onResume() {
super.onResume();
if (isFirstResume) {
isFirstResume = false;
return;
}
if (getUserVisibleHint()) {
onUserVisible();
}
}

@Override
public void onPause() {
super.onPause();
if (getUserVisibleHint()) {
onUserInvisible();
}
}

private boolean isFirstVisible = true;
private boolean isFirstInvisible = true;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
if (isFirstVisible) {
isFirstVisible = false;
initPrepare();
} else {
onUserVisible();
}
} else {
if (isFirstInvisible) {
isFirstInvisible = false;
onFirstUserInvisible();
} else {
onUserInvisible();
}
}
}

public synchronized void initPrepare() {
if (isPrepared) {
onFirstUserVisible();
} else {
isPrepared = true;
}
}

/**
* 第一次fragment可见(进行初始化工作)
*/
public abstract void onFirstUserVisible();

/**
* fragment可见(切换回来或者onResume)
*/
public abstract void onUserVisible();

/**
* 第一次fragment不可见(不建议在此处理事件)
*/
public abstract void onFirstUserInvisible();

/**
* fragment不可见(切换掉或者onPause)
*/
public abstract void onUserInvisible();

}


如上代码,使用setUserVisibleHint方法作为回调的依据,
暴露出来让子类使用的新的生命周期方法为:

- onFirstUserVisible();
第一次fragment可见(进行初始化工作)

- onUserVisible();
fragment可见(切换回来或者onResume)

- onFirstUserInvisible();
第一次fragment不可见(不建议在此处理事件)

- onUserInvisible();
fragment不可见(切换掉或者onPause)

据说具体的效果是:

1. 首先加载ViewPager,回调FragmentA(第一个默认呈现的Fragment)的onFirstUserVisible(),可以在这里进行FragmentA的初始化工作,其他Fragment保持不变。

2. 用户从FragmentA滑动到FragmentB,回调FragmentA的onUserInvisible()、FragmentB的onFirstUserVisible()(因为第一次切换到FragmentB,可以在这里进行初始化工作)。

3. 用户从FragmentB滑动到FragmentC,回调FragmentB的onUserInvisible()、FragmentC的onFirstUserVisible()(因为第一次切换到FragmentC,可以在这里进行初始化工作)。

4. 用户从FragmentC滑动到FragmentB,回调FragmentC的onUserInvisible()、FragmentB的onUserVisible()(因为FragmentB之前已经被加载过)。

5. 因为到此为止,suoyou的Fragment都已经被加载过了,所以以后这3个Fragment互相任意切换,只会回调原来Fragment的onUserInvisible()和切换后的Fragment的onUserVisible()。

6. 用户处于FragmentB,关闭手机屏幕,回调FragmentB的onUserInvisible()。

7. 用户处于FragmentB,手机屏幕处关闭状态,然后开启手机屏幕解锁,只回调FragmentB的onUserVisible()。

可我TM无论怎么调试都没这个效果好吗,TMD setUserVisibleHint()就是不调用,不执行!!!

问度娘TMD都有是千篇一律的是使用fragment的setUserVisibleHint()方法实现懒加载,使用fragment的setuservisiblehint ()方法实现懒加载,使用fragment的setUserVisibleHint()方法实现懒加载;我去!!!我都快崩溃了好吗。

无果只能求助国外的网友了,竖上梯子问google(搜索 fragment setuservisiblehint not called)我的男神去了,打开第一条搜索结果,这个结果是我的另一个男神:

,这就是我正想要的,国外的网友给的答案如下:



答案大致意思是:需要 FragmentPagerAdapter 显示的对setUserVisibleHint()方法的调用,查看自己的adapter原来是继承的PagerAdapter 而不是FragmentPagerAdapter,于是果断重新生成一个继承 FragmentPagerAdapter 的 adapter,

代码如下:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import java.util.ArrayList;
import java.util.List;

public class SimpleFragmentPagerAdapter  extends FragmentPagerAdapter {
private List<Fragment> listFragments;
private List<String> mTitleList = new ArrayList<>();//页卡标题集合

public SimpleFragmentPagerAdapter(FragmentManager fm,
List<Fragment> al,
List<String> titleList) {
super(fm);
listFragments = al;
mTitleList =  titleList;
}

public SimpleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int position) {
return listFragments.get(position);
}

@Override
public int getCount() {
return listFragments.size();
}

@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}

@Override
public CharSequence getPageTitle(int position) {
return mTitleList.get(position);//页卡标题
}
}


然后将该adapter赋予Viewpager ,经调试成功了,setUserVisibleHint()方法终于起作用了,懒加载也有了。

项目源码:https://github.com/Leevey/LazyLoadFragment

参考文献:

实现类似微信的延迟加载的Fragment——LazyFragment

stackoverflow:Is Fragment.setUserVisibleHint() called by the android System?

FragmentPagerAdapter.java的源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: