android-ViewPager的轮播
报错:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.这种异常是该控件在前面已经添加过一个父控件,当再次滑动重复执行instantiateItem方法,会重复添加,解决方法是先判断其父容器是否存在,如存在,先和此子控件解除关系
@Override public Object instantiateItem(ViewGroup container, int position) { View view = this.list.get(position % list.size()); //判断其父容器是否存在,如存在,先和此子控件解除关系 ViewPager parent = (ViewPager) view.getParent(); if (parent != null) { parent.removeView(view); } container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { //destroyItem()方法中可以不写任何东西效果会好一点 }当使用ViewPager滑动发生java.lang.IllegalStateException: The specified child already has a parent.异常时的解决方案
Android使用ViewPager实现左右循环滑动及轮播效果
adapter中:
@Override public int getCount() { return Integer.MAX_VALUE; } @Override public Object instantiateItem(ViewGroup container, int position) { View view = this.list.get(position % list.size()); container.addView(view); return view; }然后设置当前viewpager的item在中间某一个值即可。如下:
mViewPager.setCurrentItem(imgRes.length * 1000);Android ViewPager 无限循环左右滑动(可自动) 实现
设置是否自动轮播的关键:
//根据isLoop设置是否轮播 mTimer.schedule(new TimerTask() { @Override public void run() { Message message = new Message(); message.what = UPDATE_VIEWPAGER; if(isLoop){ //如果isLoop = true 才进行轮播 handler.sendMessage(message); } } }, 1000, 1000);//这里定义了轮播图切换的间隔时间ViewPager自动轮播,手指按住停止轮播
直接看张鸿洋的博客:
巧用ViewPager 打造不一样的广告轮播切换效果
GitGub地址
使用张鸿洋炫酷的轮播viewpager发现,手动向左滚动时,右侧刚进来的一张图片会卡顿延迟(自动轮播表现不明显)。
参考:Andriod性能优化之列表卡顿——以“简书”APP为例 Android开发者选项——Gpu呈现模式分析
通过开发者模式-Gpu呈现模式分析,发现
后来查看了布局,发现:主界面四个tab上面也是一个viewpager。
原来是viewpager 与 viewpager的fragment中的viewpager滑动冲突了。
然后优化:将主界面四个tab上面改为一个空白viewgroup。替换布局直接切换fragment:add、show、hide。
优化效果:
上面优化完毕,但是发现手动左滑,右侧的图片进入时依然会卡顿。
根据鸿洋大神的博客对比发现,我写的适配器的数据源在fragment中new ImageView 好了之后传进adapter。鸿洋是在adapter中new ImageView,按照鸿洋的设计,果然不卡顿了。
原来有问题的代码:
@Override public Object instantiateItem(ViewGroup container, int position) { View view = this.list.get(position % list.size()); //判断其父容器是否存在,如存在,先和此子控件解除关系 ViewPager parent = (ViewPager) view.getParent(); if (parent != null) { parent.removeView(view); } container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { //destroyItem()方法中可以不写任何东西效果会好一点 }估计就是addview前会remove加载过的view,由此造成卡顿。removeView只是从container中移除view,此view不一定会被回收。但是耗费时间。
mViewPager.setOffscreenPageLimit(3);//决定哪些会被回收。完善后的代码:
public class DiscoverPagerAdapter extends PagerAdapter { private int[] imgRes; private Context context; public DiscoverPagerAdapter(Context context, int[] imgRes) { this.context = context; this.imgRes = imgRes; } @Override public int getCount() { return Integer.MAX_VALUE; } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public Object instantiateItem(ViewGroup container, final int position) { ImageView view = new ImageView(context); view.setScaleType(ImageView.ScaleType.FIT_XY); view.setImageResource(imgRes[position % imgRes.length]); container.addView(view); view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "position===" + position, Toast.LENGTH_LONG).show(); } }); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } }这种方法在每次初始化一个page时都new一个ImageView,由于setOffscreenPageLimit的回收,不会导致内存问题。
3、每次初始化下一页太耗时导致显示延迟卡顿,所以可以添加缓存:
mViewPager.setOffscreenPageLimit(3);