使用viewpager默认会加载至少一个view,项目中有的页面中的大图比较多,如果一起加载比较耗时,并且浪费数据流量,我们想把viewpager滑动到哪页加载哪页,也就是viewpager懒加载方法。
首先看下Activity
private void initView() {
mPagerAdapter.addFragment(new OnlineArtistWesternFragment(OnlineArtistsActivity.this));
mPagerAdapter.addFragment(new OnlineArtistChinaFragment(OnlineArtistsActivity.this));
mPagerAdapter.addFragment(new OnlineArtistJapanFragment(OnlineArtistsActivity.this));
mViewPager.setPageMarginDrawable(R.drawable.viewpager_margin);
mViewPager.setOffscreenPageLimit(mPagerAdapter.getCount());
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(1);
initScrollableTabs(mViewPager);
}
/**
* Initiate the tabs
*/
public void initScrollableTabs(ViewPager mViewPager) {
ScrollableTabView mScrollingTabs = (ScrollableTabView) findViewById(R.id.online_artists_scrollingTabs);
ScrollingTabsAdapter mScrollingTabsAdapter = new ScrollingTabsOnlineAdapter(
OnlineArtistsActivity.this);
mScrollingTabs.setAdapter(mScrollingTabsAdapter);
mScrollingTabs.setViewPager(mViewPager);
fragment.java
onActivityCreate中
if (getUserVisibleHint() && isVisibleToUser){//getUserVisibleHint() 方法判断界面是否可见
requestForData();
}
这样做的作用是初始化时之加载当前view的数据,而不加载其他view的数据。保证初始化只加载一个view的数据
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {//设置当前界面可见
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser)
this.isVisibleToUser = true;
}
public void requestForData(){ //对外部提供方法,当界面滑动时请求数据加载
if (!isInit) {//确保只加载一次
requestForManInArea();//异步加载,加载完后刷新UI
requestForWomanArea();
requestForCombinationArea();
isInit = true;
}
}
viewpager的滑动监听
@Override
public void onPageSelected(int position) {
selectTab(position);
if (mPager.getAdapter() instanceof PagerAdapter){
PagerAdapter pagerAdapter = (PagerAdapter) mPager.getAdapter();
if (pagerAdapter.getItem(position) instanceof OnlineArtistsFragment){
OnlineArtistsFragment onlineArtistsFragment = (OnlineArtistsFragment) pagerAdapter.getItem(position);
if (mPager.getCurrentItem() == 1)
return;
onlineArtistsFragment.requestForData();//请求数据加载
}
}
}
当我们设置mViewPager.setCurrentItem(1);时
会报出空指针,位置在我们调用控件引用刷新UI的地方。
查看ViewPager.java
public void setCurrentItem(int item, boolean smoothScroll) {
mPopulatePending = false;
setCurrentItemInternal(item, smoothScroll, false);
}
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
setCurrentItemInternal(item, smoothScroll, always, 0);
}
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
if (mAdapter == null || mAdapter.getCount() <= 0) {
setScrollingCacheEnabled(false);
return;
}
if (!always && mCurItem == item && mItems.size() != 0) {
setScrollingCacheEnabled(false);
return;
}
if (item < 0) {
item = 0;
} else if (item >= mAdapter.getCount()) {
item = mAdapter.getCount() - 1;
}
final int pageLimit = mOffscreenPageLimit;
if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
// We are doing a jump by more than one page. To avoid
// glitches, we want to keep all current pages in the view
// until the scroll ends.
for (int i=0; i<mItems.size(); i++) {
mItems.get(i).scrolling = true;
}
}
final boolean dispatchSelected = mCurItem != item;
if (mFirstLayout) {//如果是第一次加载
// We don't have any idea how big we are yet and shouldn't have any pages either.
// Just set things up and let the pending layout handle things.
mCurItem = item;
if (dispatchSelected && mOnPageChangeListener != null) {
mOnPageChangeListener.onPageSelected(item);
}
if (dispatchSelected && mInternalPageChangeListener != null) {
mInternalPageChangeListener.onPageSelected(item);
}
requestLayout();
} else {
populate(item);
scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}
}
看代码我们知道,在setCurrentItem方法中,判断是否是第一次加载,如果是,首先调用滑动监听的onPageSelected回调方法,然后在requestLayout绘制界面
这样的话 在滑动监听中,我们调用了fragment的reqestData方法,其中会用到布局控件的引用,但是界面还没有绘制,控件引用还没有初始化导致空指针问题。
解决方法:
在滑动监听的onPageSelected回调中判断position的值如果与我们设置的setCurrentItem 的position一样,就return掉,让viewPager直接去绘制界面。
否则请求数据加载。
if (mPager.getCurrentItem() == 1)
return;