天天看點

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);

    }

    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;

繼續閱讀