美文网首页
ViewPager(一):加载机制与优化

ViewPager(一):加载机制与优化

作者: bug音音 | 来源:发表于2021-01-03 11:43 被阅读0次

    前言

       以前用viewPager做轮播图,左右滑动感觉挺流程,没感觉有卡顿的现象;但实现现在又用viewPager做日历,日历的模块全部是用canvas画出来的,在这里有一些算法要去处理,viewpager左右滑动好像没那么流畅了。这个时候我就在想如何优化viewpager,尽量让它左右滑动的时候不那么卡顿,至少测试不找自己麻烦。先要研究如何优化,那么就一定要了解viewPager的预加载机制。
    

    正文

    首先我们将viewpager的可滑动范围设置为3000,在这里我故意设置成3000

      public YueLiAdapter(Context context, TypedArray array, YueLiView monthCalendarView, Class clzz, Resources resources) {
            mContext = context;
            mArray = array;
            mMonthCalendarView = monthCalendarView;
            mViews = new SparseArray<>();
            mSkinClzz = clzz;
            mSkinResources = resources;
            mMonthCount = array.getInteger( R.styleable.YueLiView_yueli_count, 3000 );
        }
    
        @Override
        public int getCount() {
            return mMonthCount;
        }
       @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Log.i("getCount", "###"+position+"  " );
    }
    

    那么初始化的时候,我们发现日志出现了这么3条信息

    image
       没错就是这3条信息,最开始的时候打印了1500,我们发现这个数字就是3000的一半,是的,在初始化的时候我们设置了getCount()的数值是3000,那么在执行instantiateItem(ViewGroup container,int position)的时候,这里面的position的值就是1500,viewPager自动会从position=getCount()/2位置加载最开始的页面,然后向前预加载一个页面,再向后预加载一个页面,也就是加载了position=1499的页面和position=1501的页面。
    

    我们移动页面

    image
       当我们再向左滑动一页的时候,那么这个时候viewPager显示的是position=1501的页面,但是它还会再向后面再预加载一个页面,也就是position=1502的页面。如果一直向后就一直预加载,直到当position=3000的时候就不会预加载了。那么向前预加载也是这样的原理,当我们的页面在position=1501这个页面的时候再向右滑动一页,那么当前显示的就是position=1500的页面,viewPager也会再向前预加载一个页面,也就是position=1499的页面。
    
       那么问题就来了,position=1499的这个页面不是已经加载过了吗,再加载一遍不是又要浪费性能了吗?那么怎么能让加载过的页面不再加载了呢?其实我们可以用sparseArray去保存加载过的页面,如果下次再预加载的时候,已经保存过的页面就不用在加载了,这样就不用再耗费性能了、也就没那么卡顿了。那么为什么用sparseArray而不用hashMap,其实sparseArray性能更好,更加节省内存,这里就不多做解释了。
    
    public class YueLiAdapter extends PagerAdapter {
     
        private SparseArray<YueView> mViews;//用sparseArray保存加载过的页面
        private Context mContext;
        private TypedArray mArray;
        private YueLiView mMonthCalendarView;
        private int mMonthCount;
        private Class mSkinClzz;
        private Resources mSkinResources;
     
        public YueLiAdapter(Context context, TypedArray array, YueLiView monthCalendarView, Class clzz, Resources resources) {
            mContext = context;
            mArray = array;
            mMonthCalendarView = monthCalendarView;
            mViews = new SparseArray<>();
            mSkinClzz = clzz;
            mSkinResources = resources;
            mMonthCount = array.getInteger( R.styleable.YueLiView_yueli_count, 3000 );//初始化范围为3000
     
        }
     
        @Override
        public int getCount() {
            return mMonthCount;
        }
     
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
        
            if (mViews.get( position ) == null) {//首先判断mViews中是否保存了之前加载过的页面,如果没有加载过就加载,如果加载过了,那么就不用加载了
                int date[] = getYearAndMonth( position );
                YueView monthView = new YueView( mContext, mArray, date[0], date[1] );
                monthView.setId( position );
                monthView.setLayoutParams( new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT ) );
                monthView.skinRefresh( mSkinClzz, mSkinResources );
                monthView.invalidate();
                monthView.setOnDateClickListener( mMonthCalendarView );
                mViews.put( position, monthView );//将加载的页面view保存在sparseArray里面
            }
            container.addView( mViews.get( position ) );//从sparseArray里面获取页面view用于显示
            return mViews.get( position );//从sparseArray里面获取保存的页面view 
        }
     
        public void setSkin(Class clzz, Resources resources) {
            mSkinClzz = clzz;
            mSkinResources = resources;
            int key = 0;
            if (mViews != null && mViews.size() > 0)
                for (int i = 0; i < mViews.size(); i++) {
                    key = mViews.keyAt( i );
                    mViews.get( key ).skinRefresh( mSkinClzz, mSkinResources );
                    mViews.get( key ).invalidate();
                }
        }
     
        public void reFresh() {
            int key = 0;
            if (mViews != null && mViews.size() > 0)
                for (int i = 0; i < mViews.size(); i++) {
                    key = mViews.keyAt( i );
                    mViews.get( key ).invalidate();
                }
        }
     
        private int[] getYearAndMonth(int position) {
            int date[] = new int[2];
            DateTime time = new DateTime();
            time = time.plusMonths( position - mMonthCount / 2 );
            date[0] = time.getYear();
            date[1] = time.getMonthOfYear() - 1;
            return date;
        }
     
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView( (View) object );
        }
     
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
     
        public SparseArray<YueView> getViews() {
            return mViews;
        }
     
        public int getMonthCount() {
            return mMonthCount;
        }
     
    }
    

    相关文章

      网友评论

          本文标题:ViewPager(一):加载机制与优化

          本文链接:https://www.haomeiwen.com/subject/oeamoktx.html