ViewPager + Volley 异步多线程图片加载实现Banner效果

来源:互联网 发布:手机淘宝不能开店 编辑:程序博客网 时间:2024/06/06 09:27
前提:使用过Volley,熟悉实现PagerAdapter引用:http://www.it165.net/pro/html/201406/15240.html

首先,布局文件与图形

  • 主布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <android.support.v4.view.ViewPager android:layout_width="match_parent"            android:layout_height="match_parent"            android:id="@+id/view_pager">            </android.support.v4.view.ViewPager>        <LinearLayout            android:id="@+id/indicator"            android:orientation="horizontal"            android:layout_width="match_parent"            android:layout_height="100px"            android:layout_alignParentBottom="true"            android:gravity="center_horizontal"></LinearLayout>        </RelativeLayout></LinearLayout>
  • ViewPager的Item布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent">    <TextView        android:id="@+id/text_view"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <ImageView        android:id="@+id/image"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>
  • 指示图标(小点点) - 未选择状态
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="oval">    <size android:width="20dp" android:height="20dp"/>    <solid android:color="#949693"/></shape>
  • 指示图标(小点点) - 选择状态
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="oval">    <size android:width="20dp" android:height="20dp"/>    <solid android:color="#97C606"/></shape>

第二步,实现PagerAdpater

    private class MyAdapter extends PagerAdapter{        //这个列表中的View是实例化后的view_pager_item,        // 只加载了文字,尚未加载图片,因为图片采用异步的方式加载        private List<View> mList;        //Volley的请求队列        private RequestQueue mRequestQueue;        //上下文,这个建立请求必须        private Context mContext;        public MyAdapter(Context context,List<View> list){            mContext = context;            //建立requestQueue            mRequestQueue = Volley.newRequestQueue(context);            mList = list;        }        @Override        public Object instantiateItem(final ViewGroup container, final int position) {            //取余才能正确获取到urls和mList            final int cur_position = position%urls.length;            //实例化ImageLoader,其中CustomeImageCache为自定义的Cache,下面会给出            ImageLoader loader = new ImageLoader(mRequestQueue,new CustomeImageCache());            //发送请求,如果有缓存,则直接返回,如果没有则发送网络请求加载图片            ImageLoader.ImageContainer imageContainer = loader.get(urls[cur_position], new ImageLoader.ImageListener() {                @Override                public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {                    //isImmediate 为 true 可以设置默认图片                    View view = mList.get(cur_position);                    ImageView image = (ImageView) view.findViewById(R.id.image);                    image.setImageBitmap(response.getBitmap());                    //先移除,在添加,不然就会报出 已存在父容器的异常                    container.removeView(mList.get(cur_position));                    container.addView(mList.get(cur_position));                 }                @Override                public void onErrorResponse(VolleyError error) {                    //这里可以加载错误图片                }            });            //如果有缓存            if(imageContainer.getBitmap() != null){                View view = mList.get(cur_position);                ImageView image = (ImageView) view.findViewById(R.id.image);                image.setImageBitmap(imageContainer.getBitmap());                container.removeView(mList.get(cur_position));                container.addView(mList.get(cur_position));            }            return mList.get(cur_position);        }        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            final int cur_position = position%urls.length;            container.removeView(mList.get(cur_position));        }        @Override        public int getCount() {            //让ViewPager无限滚动            return Integer.MAX_VALUE;        }        @Override        public boolean isViewFromObject(View view, Object object) {            return view==object;        }    }

自定义图片缓存类

    static class CustomeImageCache implements ImageLoader.ImageCache{        LruCache<String,Bitmap> mCache;        public CustomeImageCache(){            int max =1024 * 1024 * 1024;            mCache = new LruCache<>(max);        }        @Override        public Bitmap getBitmap(String url) {            return mCache.get(url);        }        @Override        public void putBitmap(String url, Bitmap bitmap) {            mCache.put(url,bitmap);        }    }

在实现的过程中,我有个疑问,看下面的代码(不完整)。

 ImageLoader.ImageContainer imageContainer = loader.get(urls[cur_position], new ImageLoader.ImageListener() {                @Override                public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {                    //isImmediate 为 true 可以设置默认图片                    View view = mList.get(cur_position);                    ImageView image = (ImageView) view.findViewById(R.id.image);                    image.setImageBitmap(response.getBitmap());                    //先移除,在添加,不然就会报出 已存在父容器的异常                    container.removeView(mList.get(cur_position));                    container.addView(mList.get(cur_position));                }

显而易见,我们对UI进行了操作,但是这并不是在主线程中,可是却有效果。带着疑问去看了ImageLoader的源码。看到了这个。。

    /** Handler to the main thread. */    private final Handler mHandler = new Handler(Looper.getMainLooper());

原来这里获取了主线程的Looper,所以能去更新UI.下面给出那个方法。

   /**     * Starts the runnable for batched delivery of responses if it is not already started.     * @param cacheKey The cacheKey of the response being delivered.     * @param request The BatchedImageRequest to be delivered.     */    private void batchResponse(String cacheKey, BatchedImageRequest request) {        mBatchedResponses.put(cacheKey, request);        // If we don't already have a batch delivery runnable in flight, make a new one.        // Note that this will be used to deliver responses to all callers in mBatchedResponses.        if (mRunnable == null) {            mRunnable = new Runnable() {                @Override                public void run() {                    for (BatchedImageRequest bir : mBatchedResponses.values()) {                        for (ImageContainer container : bir.mContainers) {                            // If one of the callers in the batched request canceled the request                            // after the response was received but before it was delivered,                            // skip them.                            if (container.mListener == null) {                                continue;                            }                            if (bir.getError() == null) {                                container.mBitmap = bir.mResponseBitmap;                                container.mListener.onResponse(container, false);                            } else {                                container.mListener.onErrorResponse(bir.getError());                            }                        }                    }                    mBatchedResponses.clear();                    mRunnable = null;                }            };            // Post the runnable.            mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);        }    }

Volley确实很好用啊,省了点事。

下一步,初始化Layout与ViewPager

onCreate方法

   @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        mViewPager = (ViewPager) findViewById(R.id.view_pager);        List<View> list = new ArrayList<>();        mInflater = LayoutInflater.from(this);        /*        * 创建多个item 每一条都是一个item        * 从服务器获取完数据(文章标题、url地址)后,在设置适配器        * */        View item = null;         for(int i=0; i<urls.length; i++){            item = mInflater.inflate(R.layout.view_pager_item,null);             ((TextView)item.findViewById(R.id.text_view)).setText("第" + i +"个" );             list.add(item);        }        //创建适配器,把组装完的组件传递进去        MyAdapter myAdapter = new MyAdapter(this,list);        mViewPager.setAdapter(myAdapter);        //绑定监听,Viewpager的页面监听        mViewPager.setOnPageChangeListener(new MyListener());        //初始化指示器(下方给出代码)        //将第一个点点选中,其他的不选中        initIndicator();        //设置定时器,延时两秒后,每两秒进行一次滚动        Timer timer = new Timer();        timer.schedule( new TimerTask(){            @Override            public void run() {                handler.sendEmptyMessage(0x123);            }        },2000,2000);     }

Handler

    Handler handler = new Handler(){        private boolean mIsPause = false;        @Override        public void handleMessage(Message msg) {            if(msg.what == 0x123) {                //滚动                if (!mIsPause) {                    mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);                }            }else if(msg.what == 0x234){                //停止滚动                mIsPause = true;            }else if(msg.what == 0x345){                //开始滚动                mIsPause = false;            }        }    };

initIndicator() 初始化指示器

    /**     * 初始化引导图标     * 动态创建多个小圆点,然后组装到线性布局里     */    private void initIndicator() {        ImageView imageView;        View v = findViewById(R.id.indicator);        for(int i = 0 ; i< mIndicatorImgs.length; i++){            imageView = new ImageView(this);            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(10,10);            layoutParams.setMargins(7,10,7,10);            imageView.setLayoutParams(layoutParams);            mIndicatorImgs[i] = imageView;            if(i==0){                mIndicatorImgs[i].setBackgroundResource(R.drawable.indicator_selected);            }else{                mIndicatorImgs[i].setBackgroundResource(R.drawable.indicator);            }            ((ViewGroup)v).addView(mIndicatorImgs[i]);        }    }

ViewPager的页面变化监听实现

    private class MyListener implements ViewPager.OnPageChangeListener{        @Override        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {        }        @Override        public void onPageSelected(int position) {            int cur_position = position%urls.length;            for(int i=0; i<mIndicatorImgs.length; i++){                mIndicatorImgs[i].setBackgroundResource(R.drawable.indicator);            }            mIndicatorImgs[cur_position].setBackgroundResource(R.drawable.indicator_selected);        }        @Override        public void onPageScrollStateChanged(int state) {            if(ViewPager.SCROLL_STATE_DRAGGING == state){                //用户碰到了                handler.sendEmptyMessage(0x234);            }else{                //用户离开了                handler.sendEmptyMessage(0x345);            }        }    }

当用户碰到了ViewPager获取正在移动ViewPager,则向handler发送消息,让timerTask发送过来的定时任务不处理,当ViewPager闲置后,handler发送消息,开始处理任务。

声明的成员变量

  private ViewPager mViewPager;    private LayoutInflater mInflater;    private ImageView[] mIndicatorImgs = new ImageView[7];    String[] urls = {            "http://a.hiphotos.baidu.com/image/pic/item/3bf33a87e950352ad6465dad5143fbf2b2118b6b.jpg",            "http://a.hiphotos.baidu.com/image/pic/item/c8177f3e6709c93d002077529d3df8dcd0005440.jpg",            "http://f.hiphotos.baidu.com/image/pic/item/7aec54e736d12f2ecc3d90f84dc2d56285356869.jpg",            "http://e.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de308a87fc96eef01f3a297969.jpg",            "http://d.hiphotos.baidu.com/image/pic/item/f31fbe096b63f624b88f7e8e8544ebf81b4ca369.jpg",            "http://h.hiphotos.baidu.com/image/pic/item/11385343fbf2b2117c2dc3c3c88065380cd78e38.jpg",            "http://c.hiphotos.baidu.com/image/pic/item/3801213fb80e7bec5ed8456c2d2eb9389b506b38.jpg"    };

完整代码详见:https://github.com/ding102992/scrollbannerdemo

0 0
原创粉丝点击