ViewPager延時加載(懶加載)

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

發佈了60 篇原創文章 · 獲贊 3 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章