ViewPager大家经常用到的一个控件,经常会需要取消它的预加载功能。
下面贴一段代码可以完美实现懒加载功能,亲测可用。
首先需要写一个基类,所有需要懒加载的都继承这个类。这里只写了一些重要方法的实现,其他基类中的方法根据自己的需求添加
/**
*
* ViewPager + Fragment 结构中
* ViewPager 有预加载功能,在访问网络的时候会同时加载多个页面的网络,体验很不好,
更会影响一些带有页面进度条的显示
* 所以ViewPager中的Fragment 都继承这个类。 效果是只预加载布局,但是不会访问网络。
*/
public abstract class LazyBaseFragment extends Fragment {
public View view;
/**
* Fragment当前状态是否可见
*/
protected boolean isVisible;
/**
* 初始化view对象,这里在Fragment中的onCreateView方法中进行实现,返回一个View对象
*/
public abstract View initView();
/**
* 初始化数据
*/
public abstract void initData();
//先于oncreatview执行的方法
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
/**
* 可见
*/
protected void onVisible() {
lazyLoad();
}
/**
* 不可见
*/
protected void onInvisible() {
}
/**
* 延迟加载
*/
protected abstract void lazyLoad();
}
下面贴一段具体实现类的代码
/**
*
* 用于首页Viewpager+Fragment中的 Fragment
*/
public class ViewPagerFragment extends LazyBaseFragment {
private static final String tag = "ViewPagerFragment";
private static final int SUCCESS = 11;
/**
* 标志位,标志已经初始化完成
*/
private boolean isPrepared;
/**
* 是否已被加载过一次,第二次就不再去请求数据了
*/
private boolean mHasLoadedOnce;
// 以上两个变量至关重要,主要靠这两个变量实现
@Bind(R.id.listView)
PullToRefreshListView pullToRefreshListView;
@Bind(R.id.layout_requsest_fail)
LinearLayout layout_requsest_fail;
@Bind(R.id.butTryAgain)
Button butTryAgain;
int page = 1;
String type = "";
private ViewPagerAdp adp;
private PageDialog pageDialog;
public ViewPagerFragment(int type) {
this.type = type + "";
}
public ViewPagerFragment() {
}
//这里的代码是一两年前的,当时网络底层还是用handler进行传输数据,
// 这里就是实现网络数据请求结果的代码。在请求到正确的结果以后,记得将
//mHasLoadedOnce 置为true 。
@Override
protected void handleMsg(Message msg) {
switch (msg.what) {
case Constant.NETWORK_MEG_WHAT_FAILURE_1:
pullToRefreshListView.onRefreshComplete();
if(null!= pageDialog){
pageDialog.dismiss();
}
Bundle b1 = msg.getData();
if(null!=b1){
String failureMsg = b1.getString(Constant.NETWORK_FAILURE);
}
layout_requsest_fail.setVisibility(View.GONE);
ToastUtlis.showShort(getActivity(), failureMsg);
break;
case Constant.NETWORK_MEG_WHAT_ERROR_2:
// 网络错误
pullToRefreshListView.onRefreshComplete();
if(null!= pageDialog){
pageDialog.dismiss();
}
layout_requsest_fail.setVisibility(View.VISIBLE);
ToastUtlis.showShort(getActivity(), getResources().getString(R.string.network_error));
break;
case SUCCESS:
if (mHasLoadedOnce != true) {
mHasLoadedOnce = true;
}
if(null!= pageDialog){
pageDialog.dismiss();
}
pullToRefreshListView.onRefreshComplete();
layout_requsest_fail.setVisibility(View.GONE);
String data = msg.getData().getString(Constant.NETWORK_SUCCESS);
LogUtils.i("网络", "成功" + msg.getData().getString(Constant.NETWORK_SUCCESS));
//Gson解析数据
parseListData(data);
break;
default:
break;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
initView();//初始化视图
// 页面初始化已经完成 变量置为true
isPrepared = true;
initData();
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}
return view;
}
@Override
public View initView() {
//此处view为基类中的view,所以方法最后返回了null
view = View.inflate(getActivity(), R.layout.fragment_viewpagerfragment, null);
pageDialog = new PageDialog(getActivity());//页面进度条
ButterKnife.bind(this, view);
return null;
}
/**
*初始化数据的方法。 注意: 当请求网络成功以后, 一定要将 mHasLoadedOnce 置为true !!!
*/
@Override
public void initData() {
if (!isPrepared || !isVisible || mHasLoadedOnce) {
return;
}
requestNet(); //发起网络请求的方法
}
private void requestNet() {
// 这个方法里面是发起网络请求的具体实现, pageDialog是项目中使用的页面进度条,这个可以忽略
pageDialog.show();
//
}
public void parseListData(String result) {
//解析数据
}
// 这里要特别注意,这个lazyLoad一定要重写,并且里面实现initData方法。
//这里因为代码实现非常少,所以经常被人忽略,特此提醒
@Override
protected void lazyLoad() {
initData();
}
}
因为代码是之前的代码,删掉了一些没用的,这样看起来清晰一点。下面解释一下流程和用意。
在基类中 setUserVisibleHint()这个方法是先于fragment初始化方法oncreateView执行的,如果当前页面在显示中,getUserVisibleHint()就为true,否则为false。
viewpager预加载时,页面不显示,isVisible为false。
然后开始对fragment的预加载过程,在fragment的oncreateview执行时,执行到initData时 ,正常的操作在这里应该请求网络数据了,但是因为在基类setUserVisibleHint中将isVisible置为false。所以initData没到请求网络时就return了,只完成了页面布局的初始化,没有请求网络。
在滑动到fragment时,setUserVisibleHint中isVisible为true,并且调用lazyLoad(注意,此时fragment的oncreateview早已执行过,并且只会执行一次, 所以一定要在实现类中的lazyLoad实现initData方法,不然只是个空方法,不会加载数据),实现类中lazyLoad的具体实现为数据的初始化,此时,页面布局已经完成初始化,当前页面也在显示中,并且数据也没有加载过,三个变量的条件都满足, 去执行数据加载的过程(接收intent或者请求网络数据等)。
由此实现了整个过程,在预加载时只执行了initview初始化了布局,然后在页面显示的时候去执行initData初始化数据。
网友评论