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
- ViewPager + Volley 异步多线程图片加载实现Banner效果
- 使用Volley实现ListView异步加载图片
- Volley+ViewPager加载网络图片
- ViewPager异步加载图片
- 使用Banner实现图片的轮番显示的效果,替换ViewPager + CirclePagerIndicator
- Volley框架学习(二)使用Volley实现异步加载图片
- ViewPager实现加载网络图片,动态添加删除效果
- 使用Volley异步加载网络图片
- 自制的Banner轮播图 ,只需加载图片地址集合,即可实现轮播效果
- Volley实现图片加载功能
- Android 中ViewPager 实现banner无限轮播效果
- 多线程异步加载图片async_pictures
- 实现异步加载图片
- android listview viewpager 异步加载图片 headerview
- android ViewPager 简单多线程加载本地图片
- android中volley框架实现图片加载
- Volley+Cache 实现GridWall图片加载
- Android volley 应用 GET POST请求 图片异步加载
- 更改KVM虚拟机root的密码
- 佛山哪家APP开发公司最好
- 看看CameraClient 的client->initialize(mModule) 过程
- PhpStorm使用技巧小结
- 《十天学会C++——范磊主讲》读书笔记
- ViewPager + Volley 异步多线程图片加载实现Banner效果
- python初步_字符文件正则表达式
- 一个水货的阿里实习生面试经验
- 我也来写DBUtils
- 即时通讯开发——Fragment+ViewPager滑动主界面
- attachment configuration
- slave延迟很大优化方法
- 【分享】VNR翻译日语游戏汉化简易图解教材2
- 一个铁杆中医眼中的专业中医网站