现在的位置: 首页 > 综合 > 正文

ViewPager延时加载(懒加载)

2017年09月21日 ⁄ 综合 ⁄ 共 4090字 ⁄ 字号 评论关闭

使用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;

抱歉!评论已关闭.