android 的ViewPager的预加载机制,特殊的需求。

这年头,做过android的基本上都用过ViewPager,稍微熟悉的人都知道要配合PagerAdapter适配器,实现适配器的四个方法。再深入一点的知道ViewPager的预加载机制,也就是说,如果集合数据大于1,那么ViewPager刚开始时是一次加载两个View,里面最多时有3个View,不停地创建和销毁。大部分时候,控件本省提供的方法够用,怕就怕有一些特殊的需求,比如说刚进入一个ViewPager,点击一下第一个View,改变了它的样式,同时要求后面的所有View都改变。除了预加载的第二张,其他的都是重新生成的,可以在适配器里加个标示控制一下,那么,预加载的第二张怎么办?下面有几种思路。

产品有个需求,ViewPager里面包含8个页面,页面格式一致。每个页面都有 textview文字 和 imagView图片及button按钮。viewpager产生,点击imagView,textview文字隐藏,再点击,出现;如果无网络,当前图片没有加载出来,点击button重新加载,恰好有网络,图片加载出来,同时它前面和后面的包括预加载的都要加载出来。

一、修改预加载机制,使其每次加载一张,不用预加载。ViewPager的setOffscreenPageLimit(int limit),来设置ViewPager预加载的数量,但可惜的是,如果传入的参数小于1时,会自动设置为1。所以只能设置为2、3、4等等,增加预加载的数量,通过此方法禁止预加载恐怕行不通。那么,肿么办?干脆,修改源码吧,由于每个版本都有v4包,ViewPager里卖的内容也各有不同,所以,使用低版本v4包里的ViewPager,完全copy出来一份,将其中的DEFAULT_OFFSCREEN_PAGES值改为0即可,这种方法和源码网上一搜一大把,不是本文的重点,所以还需要各位百度去。这样每次都是加载一张,可以解决产品的问题。

二、在原基础上,根据适配器里面的方法,View的生成和销毁,写代码,通过逻辑,手动刷新页面。
instantiateItem(ViewGroup container,final int position)添加元素,destroyItem(ViewGroup container, int position, Object object)里面移除元素。

第一种方法,把ViewPager以参数的形式传递给适配器,在适配器里面要用到。ViewPager的集合元素大于等于3个元素时,如果当前页面在ViewPager的首页或者末尾页面,ViewPager其实是包含2个childView,处于非头部和尾部时,ViewPager含有3个childView。这是由于上述两个方法控制的,所以,此时,当点击imagView,textview文字需要隐藏,我们可以在imagView的点击事件里面加入以下代码,
private void explainClickGone() {
        for(int x = 0, childNum = mImageNewsViewPager.getChildCount();x < childNum; x++){
            tvGoneOrVisible(x);
        }
    }

    /**
     * 找到文字说明的textview,使其隐藏或出现
     * @param index
     */
    private void tvGoneOrVisible(int index) {
        View view = mImageNewsViewPager.getChildAt(index);
        if (view instanceof ViewGroup) {
            TextView tv = (TextView) view.findViewById(R.id.text);
            if (isComment) {
                tv.setVisibility(View.VISIBLE);
            } else {
                tv.setVisibility(View.GONE);
            }
        }
    }

isComment是个boolean值,通过它判断文字是隐藏还是展示;mImageNewsViewPager是ViewPager,通过遍历,拿到每一个它包含的子元素,然后拿出来,在通过findViewById找到textview文字的控件,然后就是隐藏或展示,别忘了在imagView的点击事件里,对isComment值取反。这样,预加载的图片也就被改变了,其他的都是新生产的View,可以在生产布局时根据isComment来判断文字是显示还是隐藏。
最开始是想根据是否是头部或尾部,单独改变当前页面后面一张或前面一张,但viewpager的滑动的话,来回添加移除,根据索引已经不好判断了,所以干脆整体遍历以便,反正数据量也不大。

第二种方法:以图片为例,也是把ViewPager以参数的形式传递给适配器,在适配器里面要用到。
android提供了一种优化的Map集合,SparseArray。可以写一个类,PagerImage,里面包含两个属性,String imageUrl和ImageView imageView;
在适配器里定义成员变量private SparseArray mNoLoaderImages = new SparseArray();// 无图模式下,记录没有被加载的图片的信息。在instantiateItem(ViewGroup container,final int position)里面对图片加载进行监听,如果图片加载失败了,记得在回调方法添加以下代码,mNoLoaderImages.put(position,new PagerImage(url,imageView));在图片成功加载的回调里添加mNoLoaderImages.delete(position);简单解释以下,当图片下载失败了,把图片的url和ImageView控件封装到一个bean里面,然后以position为key,存储到SparseArray集合,如果再次加载图片成功了,就把它从集合中移除出去。对SparseArray不了解的可以百度,如果还不理解,就简单的把它看成是个key和value的map集合,就像HashMap一样就行了。下一步是在button按钮的点击回调事件里,添加图片加载的逻辑。
for(int x = 0,count = mNoLoaderImages.size(); x< count; x++ ) {
                        PagerImage pagerImage = mNoLoaderImages.get(x);
                        if(pagerImage != null){
                            ImageLoader.withFitCenterForSource(mContext,pagerImage.getImageView(), pagerImage.getImageUrl());
                        }
                    }
同时,记得在
@Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        mNoLoaderImages.delete(position);
        container.removeView((View) object);
    }
否则就和容易遭成内存泄露了。 集合里都是加载图片失败的,根据position来记录的信息,然后遍历,更具position拿出url和ImageView,再次加载。逻辑理顺后,就这样了。

更多相关文章

  1. webservice二进制文件传输
  2. Android(安卓)图像绘制之 Drawable
  3. Android手机拍照
  4. Android中几种图像特效处理的集锦!
  5. Android(安卓)TextView使用HTML处理字体样式、显示图片等
  6. 关于android的9path图片处理
  7. 性能优化——Android图片压缩与优化的几种方式
  8. Android多线程下载远程图片
  9. Android(安卓)中,应用程序需要的图片资源如何针对不同屏幕大小手

随机推荐

  1. 学习文档android
  2. Android Timer类的使用
  3. Could not resolve org.jetbrains.kotlin
  4. 【FAQ】Ubuntu环境下ant编译android代码
  5. Android多媒体开发高级编程
  6. 如何开启cm android自带浏览器的谷歌书签
  7. Android(安卓)内存泄漏调试
  8. 读取android根目录下的文件或文件夹
  9. 2011.07.20——— android 获得当前view
  10. Android Stuido 更新问题