Android ViewPager 如何显示大量图片

我最近想用ViewPager 来实现类似图片Gallery的效果:即滑动的时候图片一张一张显示!先搜了一下网上关于ViewPager的用法,千篇一律的都是如下的列子:

public class MyPagerAdapter extends PagerAdapter { 
 
    List<ImageView> viewList = null;

    public MyPagerAdapter(List<ImageView> viewList) {
        this.viewList = viewList;
    }
  
    @Override  
    public int getCount() {  
        return viewList.size();  
    }  
  
    @Override  
    public boolean isViewFromObject(View arg0, Object arg1) {  
        return arg0 == arg1;//官方提示这样写  
    }  
          
    @Override  
    public void destroyItem(ViewGroup container, int position, Object object) {  
        container.removeView(viewList.get(position));//删除页卡  
    }  
          
    @Override  
    public Object instantiateItem(ViewGroup container, int position) {  
        container.addView(viewList.get(position));//添加页卡  
        return viewList.get(position);  
    }  
}

============================================================================ 
List<ImageView> viewList = new ArrayList<View>();    
View view1=LayoutInflater.from(this).inflate(R.layout.test, null);  
view1.findViewById(R.id.iv).setBackgroundResource(R.drawable.ic_launcher1);  
  
View view2=LayoutInflater.from(this).inflate(R.layout.test, null);  
view2.findViewById(R.id.iv).setBackgroundResource(R.drawable.ic_launcher2);  
  
viewList.add(view1);  
viewList.add(view2);  

MyPagerAdapter adapter = new MyPagerAdapter(viewList);  
ViewPager myViewPager = findViewById(R.id.my_view_pager);
myViewPager.setAdapter(adapter); 

上述代码用List<ImageView>记录了所有要显示的图片,然后传给PagerAdapter;如果只有少数几张图片是没有问题的,但是如果要显示100张图片呢?List<ImageView>肯定会导致内存溢出!为什么一定要创建一个List<ImageView>呢,如果所有的ImageView都事先初始化了,这就完全体现不出Adapter View 的高性能!

想一想,其实可以去掉这个List<ImageView>,修改代码如下:

public class IntruderViewPagerAdapter extends PagerAdapter {

    private Context mContext;
    private List<Integer> mDrawableResIdList;

    public IntruderViewPagerAdapter(Context context, List<Integer> resIdList) {
        super();
        mContext = context;
        mDrawableResIdList = resIdList;
    }



    @Override
    public int getCount() {
        if (mDrawableResIdList != null) {
            return mDrawableResIdList.size();
        }
        return 0;
    }

    @Override
    public int getItemPosition(Object object) {
        if (object != null && mDrawableResIdList != null) {
            Integer resId = (Integer)((ImageView)object).getTag();
            if (resId != null) {
                for (int i = 0; i < mDrawableResIdList.size(); i++) {
                    if (resId.equals(mDrawableResIdList.get(i))) {
                        return i;
                    }
                }
            }
        }
        return ViewPager.POSITION_NONE;
    }

    @Override
    public Object instantiateItem(View container, int position) {
        if (mDrawableResIdList != null && position < mDrawableResIdList.size()) {
            Integer resId = mDrawableResIdList.get(position);
            if (resId != null) {
                ImageView itemView = new ImageView(mContext);
                itemView.setDrawableResource(resId);

                //此处假设所有的照片都不同,用resId唯一标识一个itemView;也可用其它Object来标识,只要保证唯一即可
                itemView.setTag(resId);

                ((ViewPager) container).addView(itemView);
                return itemView;
            }
        }
        return null;
    }

    @Override
    public void destroyItem(View container, int position, Object object) {
        //注意:此处position是ViewPager中所有要显示的页面的position,与Adapter mDrawableResIdList并不是一一对应的。
        //因为mDrawableResIdList有可能被修改删除某一个item,在调用notifyDataSetChanged()的时候,ViewPager中的页面
        //数量并没有改变,只有当ViewPager遍历完自己所有的页面,并将不存在的页面删除后,二者才能对应起来
        if (object != null) {
            ViewGroup viewPager = ((ViewGroup) container);
            int count = viewPager.getChildCount();
            for (int i = 0; i < count; i++) {
                View childView = viewPager.getChildAt(i);
                if (childView == object) {
                    viewPager.removeView(childView);
                    break;
                }
            }
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return (view == object);
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
    }

    @Override
    public void startUpdate(View container) {
    }
    @Override
    public void finishUpdate(View container) {
    }

    public void updateData(List<Integer> itemsResId) {
        if (itemsResId == null) {
            return;
        }
        mDrawableResIdList = itemsResId;
        this.notifyDataSetChanged();
    }
}

上面代码主要修改就是:

  1. 在需要创建页面instantiateItem() 的时候才去加载图片,从而不需要List<ImageView>事先加载所有的图片,
  2. 并且给每个ItemView设置Tag来唯一标识,这样在调用PagerAdapter.getItemPosition() 的时候通过Tag来获取item的位置

下面再来看看ViewPager的源码,当PagerAdapter.notifyDataSetChanged()的时候,ViewPager到底做了哪些事情:

    void dataSetChanged() {
        boolean needPopulate = mItems.isEmpty() && mAdapter.getCount() > 0;
        int newCurrItem = -1;

        for (int i = 0; i < mItems.size(); i++) {
            final ItemInfo ii = mItems.get(i);
            final int newPos = mAdapter.<span style="background-color: rgb(255, 255, 102);">getItemPosition</span>(ii.object);

            if (<span style="background-color: rgb(255, 255, 102);">newPos == PagerAdapter.POSITION_UNCHANGED</span>) {
                continue;
            }

            if (<span style="background-color: rgb(255, 255, 102);">newPos == PagerAdapter.POSITION_NONE</span>) {
                mItems.remove(i);
                i--;
                mAdapter.destroyItem(this, ii.position, ii.object);
                needPopulate = true;

                if (mCurItem == ii.position) {
                    // Keep the current item in the valid range
                    newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1));
                }
                continue;
            }

            if (<span style="background-color: rgb(255, 255, 102);">ii.position != newPos</span>) {
                if (ii.position == mCurItem) {
                    // Our current item changed position. Follow it.
                    newCurrItem = newPos;
                }

                ii.position = newPos;
                needPopulate = true;
            }
        }

        if (newCurrItem >= 0) {
            // TODO This currently causes a jump.
            setCurrentItemInternal(newCurrItem, false, true);
            needPopulate = true;
        }
        if (needPopulate) {
            populate();
            requestLayout();
        }
    }
上面代码来自ViewPager.java,其中ArrayList<ItemInfo> mItems 用来记录ViewPager所有要显示的页面,我们发现mItems与PagerAdapter 中的DataList 并不是同步的,所以二者不是一一对应的。

其实在调用PagerAdapter.notifyDataSetChanged()的时候,ViewPager会遍历mItems,通过PagerAdapter.getItemPosition()来判断当前页面是否存在或者位置有改变,从而刷新屏幕!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值